刚刚接触Java回调的时候真是一脸懵逼,在网上也搜索了大量的资料,试图重新理解。但发现网上的各种解释,阐述的都很复杂,甚至两个类的调用关系都解释反了,误导性很强。下面从工作的应用场景上,分别Java和Android应用两个方面去理解一下。
1.多种理解:
(1)首先阐述一下,网络上最多的一个类比描述:小王有一个问题需要处理,所以向小李请教。小李说需要思考一下,解答之后再给小王回复。一段时间之后,小李打电话告诉了小王问题的答案。其中“电话号码”就可以看作是一个“回调接口”。这只是一个很感性的认识。
(2)然后阐述一下,很官方的一个描述:A类有方法c()和e(),B类有一个方法d(),方法c()中调用了方法d(),在方法d()执行过程中,又调用了e()方法。e()方法就是所说的“回调函数”。这个描述是一个抽象的认识。
(3)再说一下我自己的一个理解:就以APP层和FrameWork层为例,APP层在实现功能过程中,调用FrameWork库中的API方法fun();但是fun()方法需要APP层传下来一个参数值,才能返回一个值,供APP层去实现功能。这个fun()方法就是回调方法。
2.Java场景
下面通过一个“更改前端界面”需求的APP层和FrameWork层的调用关系来具体理解一下“回调机制”。
首先是定义一个接口,并声明“execute()"方法。
public interface CallBackInterface {
void execute();
}
应用层的实现继承这个接口,并实现对应的方法。同时开启appRun()方法。在此方法中获取一个实例,首先把继承接口的appClientOne,通过setCallBackInterface注册到了底层(只有注册在底层,底层才能调用execute()方法),然后再调用底层的方法drawPage()。很明显:appClientOne对应的是A类,appRun()对应c()方法,execute()对应e()方法。
/**
* 应用端实现回调接口
*/
public class AppClient {
public static class AppClientOne implements CallBackInterface {
@Override
public void execute() {
System.out.println("需求只是在变: 这里模拟渲染前端界面为红色");
}
public void appRun() {
FrameworkService frameworkService = new FrameworkService();
frameworkService.setCallBackInterface(new AppClientOne());
frameworkService.drawPage();
}
}
}
FrameWork层获取了注册的参数callBackInterface实例,在执行drawPage()执行完的时候,调用execute(),完成了回调。同样也很明显:FrameWork对应的就是B类,drawPage()对应d()方法。
public class FrameworkService {
private CallBackInterface callBackInterface = null;
public void setCallBackInterface(CallBackInterface callBackInterface) {
this.callBackInterface = callBackInterface;
}
/**
* 渲染前端界面颜色
*/
public void drawPage() {
//渲染前端界面的准备工作
System.out.println("渲染前端页面颜色准备工作");
//调用留给前端进行个性化定制的接口
System.out.println("选用前端个性化渲染的颜色");
callBackInterface.execute();
}
}
3.Android场景
对java回调有个具体的了解之后,再回到Android回调机制。在Android当中,回调是极为常见的,其中最典型就是“button”的点击事件,我们可以试着重新理解一下。
下面是常见的MainActivity类中相关代码。MainActivity类明显对应的就是A类,onCreate方法(对应方法c())中,获取Button的一个实例,并注册监听事件setOnclickListener,onClick()方法也进行了实现。
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button)findViewById(R.id.bottom);
btn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
//do something
}
APP层的代码很清晰了,Framework层是如何实现setOnclickListener,并调用onClick方法的呢,我们点击跳转,注册的监听事件setOnclickListener,看到代码如下,而且是View类当中的方法,Button就是继承View的嘛。
public void setOnClickListener(@Nullable OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
看到了setOnclickListener的实现,然后查找一下对应的实例mOnclickListener在哪里调用了onClick方法。看到响应View点击的有一个performClick() 方法,说明Framework层是在执行这个方法时进行了回调。
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);
notifyEnterOrExitForAutoFillIfNeeded(true);
return result;
}
相信在具体的Java场景和Android场景,和一些抽象的定义,这几种理解结合起来,会对Java的回调有一个比较具体准确的认知了。