回调函数
更新:2017-1-22
网上关于回调函数的例子很多。以下下是我的理解:
- 神话版:调用,回调。
- 直述版:A让B做某事,B做着做着发现:哎呀,不对呀,这事具体应该怎么做呀?于是,回调A中询问事件具体的实现形式。然后完成事件。——以同步回调的角度(或者理解:这事我做完了接下该你A来做了,于是回调A的方法——以异步回调的角度)
- 抽象版:首先A有某事要完成,分为动作①和动作②。A让B做某事的动作①(在B中实现动作①),B做完之后回调A 某事中的动作②(在A中实现,A懒得做了,提供方法想让B给他完成)。完成整个某事。(简之:a调用了b的方法,b开始执行,b执行完了,再调用a的方法。)
*注意:A调用B,B执行完后返回A → 只是简单的调用,没有涉及到回调,即没有回调函数的实现。 - 具体版:有A和B两类(A看成应用程序,B看成系统),A调用B的方法Bf实现动作(A可以在Bf传入相关信息,★其中包括A的引用)。Bf的方法在执行完成后,因为有了A的引用,可以回调A的Af方法。Af方法就是回调函数,用来展示,或者说完成某事。
- 终极版: 上述在回调函数中直接传入对象的引用。产生的问题(Bf方法的形参里有A的引用):①暴露了对象,即传入了A的引用(B系统得到了A的引用,万一B是竞争对手呢,不安全);②增加了耦合性,每有一个新的A出现需要重写Bf方法(因为形参需要改变)。终极大招:接口方式的回调方法。——首先定义接口,A1、A2、A3。。。可以各自实现接口,相当于有不同的动作②(此时的Af是基于接口的实现方法)。A调用B的Bf方法完成动作①后,Bf回调A中方法Af(Bf的形参现在是接口,B干不了坏事了)。
- (彩蛋)实用主义:匿名内部类。直接在方法Af实现接口。
eg:https://www.zhihu.com/question/19801131/answer/26586203
同步与异步
同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)
所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。
换句话说,就是由调用者主动等待这个调用的结果。异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。
异步回调
异步回调有点像中断调用。在A中开线程调用B,然后做自己的事。等B处理完回调A。- 同步回调
A一直等B的回调。
实现场景
例1:打个比方,有一家旅馆提供叫醒服务,但是要求旅客自己决定叫醒的方法。可以是打客房电话,也可以是派服务员去敲门,睡得死怕耽误事的,还可以要求往自己头上浇盆水。这里,“叫醒”这个行为是旅馆提供的,相当于库函数,但是叫醒的方式是由旅客决定并告诉旅馆的,也就是回调函数。而旅客告诉旅馆怎么叫醒自己的动作,也就是把回调函数传入库函数的动作,称为登记回调函数
eg:https://www.zhihu.com/question/19801131/answer/27459821
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
★解释了回调函数在实际中的意义。
例2:你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。回答完毕。
作者:常溪玲
链接:https://www.zhihu.com/question/19801131/answer/13005983
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
异步回调。A:我;B:店员。买东西事件分为两个行动,行动①:找货,A调用B执行;行动②:打电话,B回调A的电话号码。
例3:一个经典例子让你彻彻底底理解java回调机制
来源:http://blog.csdn.net/xiaanming/article/details/8703708/
3.1 有一天小王遇到一个很难的问题,问题是“1 + 1 = ?”,就打电话问小李,小李一下子也不知道,就跟小王说,等我办完手上的事情,就去想想答案,小王也不会傻傻的拿着电话去等小李的答案吧,于是小王就对小李说,我还要去逛街,你知道了答案就打我电话告诉我,于是挂了电话,自己办自己的事情,过了一个小时,小李打了小王的电话,告诉他答案是2
异步回调。A:小王;B:小李。行动①:算出答案,A调用B执行;行动②:解决问题,B回调Asolve(String result)方法。
3.2 Android View的点击方法onclick()。onclick()是一个回调方法。同步回调。
- 匿名内部类形式:匿名内部类必须实现一个接口或继承一个父类,但最多只能实现/继承一个
public class MainActivity extends Activity {
//不需要调用接口
private Button button;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button =(Button)findViewById(R.id.button1);
/**
* 直接实现接口→相当于this引用 。即调用B的Bf方法,并且new相当于传入自身接口参数
*/
button.setOnClickListener(new View.OnClickListener() {
/**
* 实现接口中的方法(回调函数)
*/
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
}
}
- 内部类形式
public class MainActivity extends Activity {
//不需要调用接口
private Button button;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button =(Button)findViewById(R.id.button1);
/**
* 相当于调用B的Bf方法,传入自身参数
*/
button.setOnClickListener(new MyClickListener)
}
/**
* 内部类,实现接口
*/
class MyClickListener implements View.OnClickListener{
/**
* 实现接口中的方法(回调函数)
*/
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
}
}
- 顶级类形式:类本身作为事件监听器
public class MainActivity extends Activity implements OnClickListener{ //调用接口
private Button button;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button =(Button)findViewById(R.id.button1);
/**
* 相当于调用B的Bf方法
* this(传入的参数):引用自身,相当于A
*/
button.setOnClickListener(this);
}
/**
* 用户点击Button时调用的回调函数,即实现接口里的方法
*/
@Override
public void onClick(View v) {
Toast.makeText(getApplication(), "OnClick", Toast.LENGTH_LONG).show();
}
}
- 2.