java 的回调机制

先抛一段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class CourseActivity extends AppCompatActivity {
private Button OkBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
...

OkBtn= (Button) findViewById(R.id.ok_btn);
OkBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//do something

}
});

...
}
}
//直接继承接口
public class CourseActivity extends AppCompatActivity implements View.OnClickListener {
private Button OkBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
...

OkBtn= (Button) findViewById(R.id.ok_btn);
OkBtn.setOnClickListener(this);
...
}

@Override
public void onClick(View view) {
//do something
}
}

这段代码写了无数次,却对其内部的逻辑一直也没理会,现在总结下。

回调

在计算机程序设计中,回调函数,或简称回调(Callback 即call then back 被主函数调用运算后会返回主函数),是指通过函数参数传递到其它代码的,某一块可执行代码的引用。这一设计允许了底层代码调用在高层定义的子程序。 维基百科

通俗来讲,就是在 A 类 ( CourseActivity 类 ) 里调用 B 类 ( Button 类) 的 b 方法(setOnClickListener),然后在 B 类里的 b 方法(setOnClickListener),再回调 A 类里的 a 方法( onClick(View view) )。

现实中的例子

点外卖为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/*
* 首先定义 We 类,代表我们本身
* 定义 TakeAway 类,代表外卖
* 定义 CallBack 接口,当外卖送到楼下后用于回调
* Main 函数中进行测试
*/
public class We implements CallBack{
private TakeAway takeAway=new TakeAway(); //外卖
//模仿一个人叫外卖
public void callTakeAway(){
//开启一个线程,用于调用外卖自己的方法,制作外卖,并且把自己类的实例传过去,让外卖回调自己
new Thread(new Runnable() {
@Override
public void run() {
takeAway.makeTakeAway(We.this);
}
}).start();
//点完外卖后,开始做其他事情,等待回调
System.out.println("我开始玩耍,静待外卖");
}
//外卖做好后会回调这个方法
@Override
public void getTakeAway() {
// TODO Auto-generated method stub
System.out.println("我拿到外卖了!开始吃吃吃!");
}
}

public class TakeAway {
//将接口作为入口参数,方便回调
void makeTakeAway(CallBack cb){
//睡眠 1 秒,模仿耗时工作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("take-away:开始做外卖");
System.out.println("take-away:打包外卖");
System.out.println("take-away:送外卖");
System.out.println("take-away:到了楼下,\n开始回调「您好,您的外卖到了下来拿一下」");
//外卖做好,进行回调
cb.getTakeAway();
}
}

public interface CallBack {
void getTakeAway();
}

public class Main {

public static void main(String[] args) {
// TODO Auto-generated method stub
We I=new We();
I.callTakeAway();
}

}

运行结果如下图

探究源码

相关函数均定义在View类中

  • 首先是回调的接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /**
    * Interface definition for a callback to be invoked when a view is clicked.
    */
    public interface OnClickListener {
    /**
    * Called when a view has been clicked.
    *
    * @param v The view that was clicked.
    */
    void onClick(View v);
    }
  • 传递要进行回调的对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /**
    * Register a callback to be invoked when this view is clicked. If this view is not
    * clickable, it becomes clickable.
    *
    * @param l The callback that will run
    *
    * @see #setClickable(boolean)
    */
    public void setOnClickListener(@Nullable OnClickListener l) {
    if (!isClickable()) {
    setClickable(true);
    }
    getListenerInfo().mOnClickListener = l; //将传过来的对象保存
    }
  • 执行回调函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    /**
    * Call this view's OnClickListener, if it is defined. Performs all normal
    * actions associated with clicking: reporting accessibility event, playing
    * a sound, etc.
    *
    * @return True there was an assigned OnClickListener that was called, false
    * otherwise is returned.
    */
    public boolean performClick() {
    final boolean result;
    final ListenerInfo li = mListenerInfo;
    if (li != null && li.mOnClickListener != null) {
    playSoundEffect(SoundEffectConstants.CLICK);
    li.mOnClickListener.onClick(this); //这里进行了回调
    result = true;
    } else {
    result = false;
    }

    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
    return result;
    }

    要执行的东西就是我们继承了 View.OnClickListener 接口,实现的 onCLick() 方法了

    1
    2
    3
    4
    @Override
    public void onClick(View view) {
    //do something
    }

总结

源码只找了相关的部分,再细致自己目前也不会,慢慢学 QAQ ,总之,回调感觉就是利用多线程,先去完成一些事情,当事情完成后再利用传过来的对象,调用原来类的方法。

windliang wechat