BruceFan's Blog

Stay hungry, stay foolish

0%

Java的回调机制

回调机制就是A类中调用B类中的某个方法C,然后B类中反过来调用A类中的方法D,D这个方法就叫回调方法。下面结合经典的例子进行说明:

  • Class A实现接口CallBack callback —— 背景1
  • Class A中包含一个Class B的引用b —— 背景2
  • Class B有一个参数为callback的方法C(CallBack callback) —— 背景3
  • A的对象a调用B的方法C(CallBack callback) —— A类调用B类的某个方法C
  • 然后b就可以在C(CallBack callback)方法中调用A的方法 —— B类调用A类的某个方法D

采用一个异步加回调的例子:小王遇到一个问题”1+1=?”,就打电话给小张,小张一下子也不知道,就跟小王说,等我办完手上的事再帮你解决,小王就对小张说,那我先去逛个街,你知道答案就打电话告诉我,说完挂了电话自己办自己的事了,过了一阵时间小张给小王打电话,告诉他答案是2。
CallBack.java

1
2
3
4
5
// 这是一个回调接口
public interface CallBack {
// 这个是小张知道答案时要调用的告诉小王的函数,也就是回调函数
public void solve(String result);
}

Wang.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
// 这个是小王,实现了一个回调接口,相当于 —— 背景1
public class Wang implements CallBack {
// 小张对象的引用,相当于 —— 背景2
private Zhang zhang;
// 小王的构造方法,持有小张的引用
public Wang(Zhang zhang) {
this.zhang = zhang;
}
// 小王通过这个方法去问小张问题
public void askQuestion(final String question) {
new Thread(new Runnable() {
public void run() {
// 小王调用小张中的方法,在这里注册回调接口
// 相当于 —— A类调用B的方法C
zhang.executeMessage(Wang.this, question);
}
}).start();
// 小王问完问题就挂了电话干别的事了
play();
}
public void play() {
System.out.println("我要去逛街了");
}
// 小张知道答案后调用此方法告诉小王,这就是所谓的小王的回调方法
public void solve(String result) {
System.out.println("小张告诉小王的答案是:" + result);
}
}

Zhang.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 这个是小张
public class Zhang {
// 相当于B类的方法C(CallBack callback) —— 背景3
public void executeMessage(CallBack callBack, String question) {
System.out.println("小王的问题:" + question);
// 模拟小张办自己的事
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 小张办完自己的事情之后想到了答案是2
String result = "答案是2";
// 于是就打电话告诉小王,调用小王中的方法,相当于 —— B类调用A的方法D
callBack.solve(result);
}
}

Test.java

1
2
3
4
5
6
7
8
// 测试类
public class Test {
public static void main(String[] args) {
Zhang zhang = new Zhang();
Wang wang = new Wang(zhang);
wang.askQuestion("1+1=?");
}
}

输出:

1
2
3
小王的问题:1+1=?
我要去逛街了
小张告诉小王的答案是:答案是2

上面的例子是异步回调,下面讲一下Android中一个典型的同步回调,onClick()方法。
现在来分析一下Android View的点击方法onClick(),onClick()是一个回调方法,当用户点击View就执行这个方法,我们用View的一个子类Button来举例。

1
2
3
4
// 这个是View的一个回调接口
public interface OnClickListener {
void onClick(View v);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 这个相当于Class A,实现了OnClickListener接口 —— 背景1
public class MainActivity extends Activity implements OnClickListener {
// Class A包含Class B的引用 —— 背景2
private Button button;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button)findViewById(R.id.button1);
// Class A调用View的方法,因为Button extends View —— A类调用B类的某个方法C
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
Toast.makeText(getApplication(), "OnClick", Toast.LENGTH_LONG).show();
}
}

下面是View类的setOnClickListener方法,就相当于B类,只贴了关键代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {
protected OnClickListener mOnClickListener;
// setOnClickListener()的参数是OnClickListener接口 —— 背景3
public void setOnClickListner(OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
mOnClickListener = l;
}
public boolean performClick() {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
if (mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
// 相当于B类调用A类的某个方法D,这个D就是所谓的回调方法
mOnClickListener.onClick(this);
return true;
}
return false;
}
}

线程run()也是一个回调方法,当执行Thread的start()方法就会回调这个run()方法,还有处理消息都比较经典。
reference
http://blog.csdn.net/xiaanming/article/details/8703708