浅析回调机制,这是一篇骚骚的文章

444 阅读6分钟

序:

先给一个,我对回调机制的认识:回调就是我不知道你调用这个 具体 干嘛,但是我知道你 大概 要干什么。
比如点击,写源码的人不知道点击按钮之后登陆,还是弹出对话框,但是写源码的人知道按钮加载出来并且人的手触摸并抬起这个动作就是点击。

我们先不看android的点击事件,我们先自己做一个回调。

第一章: 校长要去开会

想象一个场景(郑重承诺,本例不针对任何一个人,只是举例,如果引起不适,请关闭)

大家都上过学,学校的boss假设就是 校长 ,校长的工作是管理同学们好好学习,快乐成长。但是一个校长管理不过来好几千名学生,所以要把工作分给 班主任教导处主任

一个学校总有那么几个调皮捣蛋的学生,那么校长就得管管,管的方式假设有两种说(talk)和打(fuck),但是校长没时间,因为校长去开会了,就把任务交给班主任和教导处主任有可能还有别的老师。好了,校长在走之前先定义好了说和打的模块。

package TestCallBack;
/**
 * 校长类(关于类名我的英文水平就这样,爱看不看)
 * @author Robin
 *
 */
public class XiaoZhang {

    //工作的引用
    DoJob mDoJob;

    //定义工作类型
    public interface DoJob {
        void talk(String teacherName);//说

        void fuck(String teacherName, String tool);//打
    }

    //对外暴露调用位置
    public void setmDoJobCallBack(String teacherName, String tool, DoJob doJob) {
        if (doJob != null) {
            doJob.talk(teacherName);//工作是-->说
            doJob.fuck(teacherName, tool);//工作是-->打
        }
    }

}

第二章:校长走了,学生炸了,老师火了

校长走后,同学们为所欲为,班主任见状不妙,马上开始工作。

package TestCallBack;

import TestCallBack.XiaoZhang.DoJob;

/**
 * 班主任
 * 
 * @author Robin
 * 
 */
public class ClassTeacher implements DoJob {

    public void talk(String teacherName) {
        // 班主任开始跟学生交谈
        System.out.println("班主任  "+teacherName + "  开始口头教育学生");
    }

    public void fuck(String teacherName, String tool) {
        // 班主任开始干学生
        System.out.println("班主任  "+teacherName + "  开始用  " + tool + "  打学生");
    }

}

(声明,我们不提倡打学生)

班主任:喂,校长吗?我要管学生了
校长:好
于是校长就new 了一个对象,并把班主任传进来,让班主任管学生

XiaoZhang xz = new XiaoZhang();// 创建一个校长

xz.setmDoJobCallBack("李二狗", "教鞭", new ClassTeacher());

log打印如下:(用eclipse怎么了?谁不是从ec过来的。。。)
这里写图片描述

教导主任管理学生同理:

package TestCallBack;

import TestCallBack.XiaoZhang.DoJob;

/**
 * 教导处主任
 * 
 * @author Robin
 * 
 */
public class JaoDaoChuTeacher implements DoJob {
    public void talk(String teacherName) {
        // 教导处主任开始跟学生聊天
        System.out.println("教导处主任  " + teacherName + "  开始口头教育学生");
    }

    public void fuck(String teacherName, String tool) {
        // 教导处主任开始打学生
        System.out
                .println("教导处主任  " + teacherName + "  开始用  " + tool + "  打学生");
    }

}

创建对象,并执行

XiaoZhang xz = new XiaoZhang();// 创建一个校长
xz.setmDoJobCallBack("蒙哥·卡恩", "斧头", new JaoDaoChuTeacher());

log打印如下:
这里写图片描述

这个地方注意,如果我想改写教导主任的talk,fuck方法,怎么写?

xz.setmDoJobCallBack("蒙哥·卡恩", "斧头", new JaoDaoChuTeacher(){

            @Override
            public void talk(String teacherName) {
//              super.talk(teacherName);
                System.out.println(teacherName);//只打印教导主任的名字
            }

            @Override
            public void fuck(String teacherName, String tool) {
                super.fuck(teacherName, tool);//又想执行被教导主任打的方法
                System.out.println("被教导主任请去喝茶嗑瓜子");//打完之后又喝茶嗑瓜子
            }

        });

注意super,调用父类的方法。
打印如下:
这里写图片描述

第三章:校长回来了

校长发现,效果并不好,学生还是很皮,于是,校长又另请高明,既不是教导处主任,也不是班主任,是一个新的角色,他叫robin,擅长用皮鞭,怎么写? 首先肯定是要有一个校长的同意,所以需要创建一个校长对象

XiaoZhang xz = new XiaoZhang();// 创建一个校长
xz.setmDoJobCallBack("robin", "皮鞭", new DoJob() {//注意这个地方是DoJob

            public void talk(String teacherName) {
                // TODO Auto-generated method stub
                System.out.println(teacherName + " 和我谈话了");
            }

            public void fuck(String teacherName, String tool) {
                // TODO Auto-generated method stub
                System.out.println("艾妈,我被 " + teacherName + " 用 " + tool
                        + " 打了");
            }
        });

log:
这里写图片描述

完结。

最后让我们再来审视一下,开头我提出来的

回调就是我不知道你调用这个 具体 干嘛,但是我知道你 大概 要干什么。

校长让座这个管理学生的工作,校长不知道具体是谁来做,怎么做,但是校长知道管学生有说和打两种方式。这个 就是所谓的 回调函数

你以为结束了?看看右边滚动条吧,孩子。这是开始,前面都是铺垫。(Java程序员适当翻看下面内容。)
问题来了,回调有个J8用?

最早开始,大家都知道我请求网络数据,一般都有两个回调方法
onSuccess
onFailed
没错,我就是用xUtils长大的。
上网查阅资料之后,这里用到的网络回调伪代码大概如下:

public static void sendHttpRequest(final String address,
            final HttpCallbackListener listener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                try {
                ...//这里用HttpUrlConnection取到数据
                    while ((line = reader.readLine()) != null) {//流转换,得到字符串
                        response.append(line);
                    }
                    if (listener != null) {
                        // 回调onSuccess()方法,携带数据
                        listener.onSuccess(response.toString());
                    }
                } catch (Exception e) {
                    if (listener != null) {
                        // 回调onFailed()方法,携带报错信息
                        listener.onFailed(e);
                    }
                } finally {
                    if (connection != null) {
                        connection.disconnect();
                    }
                }
            }
        }).start();
    }

我之前也是似懂非懂,现在感觉明白了不少。

你以为完了?
android用到了很多回调机制,比如按钮的点击事件、线程的run()方法
下面开始讲Android里面的回调机制。
这篇文章不错,我引用一下,作者不要打我

里面说到这两个例子 1. 给RecyclerView的item添加点击事件

public class ClickAdapter extends RecyclerView.Adapter{
    //定义接口实例
    private OnClickItemListener mOnClickItemListener;

    //设置接口实例的setter方法
    public void setOnClickItemListener(OnClickItemListener onClickItemListener) {
        mOnClickItemListener = onClickItemListener;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { . . . }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) { . . . }

    @Override
    public int getItemCount() { . . . }

    public class ViewHolder extends RecyclerView.ViewHolder{
        // ...
        // 视图控件初始化
        public ViewHolder(View itemView) { . . . }
        /*绑定视图方法,在Adapter的onBindViewHolder中调用*/
        public void bindHolder(final String text) {
            mTextView.setText(text);
            if (null != mOnClickItemListener) {
                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //在点击事件中进行回调
                        mOnClickItemListener.onClick(text);
                    }
                });
            }
        }
    }
    //创建内部接口
    interface OnClickItemListener{
        void onClick(String text);
    }
}

所以,接口回调可以总结为以下4步:

  • 创建内部接口
  • 定义接口实例
  • 设置接口实例的setter方法
  • 在点击事件中进行回调

2.用子线程加载网络图片,并显示在主线程中

public class ImageUtil {
    public static void loadeIamge(final String url, final LoadeImageListener listener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                InputStream is = null;
                BufferedInputStream bis = null;
                try {
                    HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
                    connection.setConnectTimeout(5000);
                    connection.connect();
                    is = connection.getInputStream();
                    bis = new BufferedInputStream(is);
                    //拿到bitmap,通知(调用)onLoadeImageListener。
                    listener.onLoadeImageListener(BitmapFactory.decodeStream(bis));
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    CloseUtil.closeQuietly(is);
                    CloseUtil.closeQuietly(bis);
                }
            }
        }).start();
    }
    public interface LoadeImageListener {
         void onLoadeImageListener(Bitmap bitmap);
     }
}

上面的代码就是一个加载网络图片的工具类,可以发现在这里,没有定义接口实例,也没有定义接口实例的setter方法,而是直接用调用者那里传来的接口实例进行操作。

下面来看看调用者的实现:

final ImageView imageView = (ImageView) findViewById(R.id.image_view);
       ImageUtil.loadeIamge(IMG_URL, new ImageUtil.LoadeImageListener() {
           @Override
           public void onLoadeImageListener(Bitmap bitmap) {
               imageView.setImageBitmap(bitmap);
           }
       });

完。











这下真的没了。。

你需要做的是点个赞,谢谢,我要打dota去了。