浅谈 Android 中的回调机制

文章目录
  1. 1. 简介回调
  2. 2. 探究回调
  3. 3. 回调的作用
  4. 4. 参考文献

生活的悲欢离合永远在地平线之外,而眺望是一种青春的姿态。

由于回老家过年,博客的更新迟了一周,本篇应该为大年初一更新出来,如今更改时间线,作为上周博客的补更。这次,谈一谈 Android 中的回调机制,经常听人提到回调函数,那么到底什么是回调函数?

简介回调

在知乎看到个排第一的通俗解释,点赞数两千多,引用如下(有些许变动):

场景:你到一个商店买东西,刚好要的东西没有货,于是,你在店员那里留下了电话。过了几天,店里有货了,店员就打了你的电话,然后,你接到电话后就到店里取了货。

解析:你的电话号码叫做回调函数,你把电话留给店员叫做登记回调函数,店里后来有货了叫做触发回调关联的事件,店员给你打电话叫做调用回调函数,你到店里取货叫做响应回调事件

还有个更简明通俗的解释,即类似 Hollywood principle 的 “Don’t call us, we’ll call you”。

好,再看看维基百科中正式的书面解释:

回调函数,或简称回调( Callback 即 call then back,被主函数调用运算后会返回主函数),是指通过函数参数传递到其他代码的,某一块可执行代码的引用。

进一步阐明回调如下:

回调是一种双向调用模式,调用方在接口被调用时,也会调用对方的接口,意即实现了抽象类或接口的实例,实现了父类提供的抽象方法后,将该方法交还给父类来处理。更简明的说,就是实现方法交还给提供接口的父类来处理

探究回调

扩展来看,回调函数即在 A 类中定义一个方法 (FunctionA),该方法 (FunctionA) 用到了一个接口和该接口中的抽象方法 (AbstractFunc),但是抽象方法 (AbstractFunc) 没有具体的实现,需要 B 类去实现,B 类实现该方法 (AbstractFunc) 后,它本身不会去调用该方法 (AbstractFunc),而是传递给 A 类,供 A 类去调用。

下面以类比的方法一步步写一个回调函数,在 Android 回调中,最常见的是 Button 点击事件的回调

I. 不妨在 A 类中定义一个内部接口,并且给该接口定义一个抽象方法如下:

1
2
3
public interface Callback {
abstract void work();
}

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);
}

II. 在 A 类中定义该接口的一个成员变量:

1
private Callback mCallback;

View 类中获取点击事件接口的成员变量

1
2
3
4
5
6
/**
* Listener used to dispatch click events.
* This field should be made private, so it is hidden from the SDK.
* {@hide}
*/
private OnClickListener mOnClickListener;

III. 在 A 类中定义一个公共方法,用来设置该接口的对象,调用该方法给接口对象变量赋值:

1
2
3
public void setCallback(Callback callback) {
mCallback = callback;
}

View 类中注册点击事件

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 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;
}

IV. 在 A 类中调用接口对象的方法:

1
2
3
public void doWork() {
mCallback.work();
}

View 中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 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() {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
return true;
}
return false;
}

综上所述,定义典型的回调机制如下:

A 类映射到员工类 Employee:

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
public class Employee {
/**
* 定义回调接口的成员变量
*/

private Callback mCallback;

/**
* 声明回调接口
*/

public interface Callback {
abstract void work();
}

/**
* 设置回调接口对象的成员变量
*/

public void setCallback(Callback callback) {
mCallback = callback;
}

/**
* 调用回调接口对象中的方法
*/

public void doWork() {
mCallback.work();
}
}

B 类映射到老板类 Boss:

1
2
3
4
5
6
7
8
9
10
11
12
public class Boss {
private Employee mEmployee;
/**
* 为 Employee 设置回调函数,在这里定义具体的回调方法
*/

mEmployee.setCallback(new Employee.Callback() {
@Override
public void work() {

System.out.println("work");
}
});
}

比照常用的 Button 点击事件处理的代码,这里,Employee 类比 View:

1
2
3
4
5
6
7
8
9
public class TestCallback {
private Button mButton;
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 处理点击事件
}
});
}

总结如下

为了实现一个回调方法,首先,要先定义一个包含了接口的类,并且该接口中要有一个抽象方法,这个抽象方法的具体实现由其他类来完成(比如响应 Button 的点击事件,onClick() 方法里做当点击事件产生,并且该方法被调用时需要做的操作,如显示文本信息等)。而后,该方法的回调是之前包含有抽象方法的那个接口所在类去调用的(比如 onClick() 方法是当点击事件产生之后,经过一系列的事件分发,在 View 类中被调用)。

回调的作用

一般来说,类的成员变量都是数据对象,主要是用来传递数据的。回调是将一段程序作为成员变量,在特定的场合使用该段程序,此为回调的核心。

Java 是一门面向对象语言,“万事万物皆为对象”,将普通事物的共性抽取出来,而这些共性中又充斥着特性,每个不同的特性就需要交给特定的情况去处理,暴露接口可以减少很多重复,使得代码更加优雅。比如,View 具有被点击的通性,但是每个点击事件会产生不一样的事件处理,因此,Android 对外暴露一个接口中有个 onClick() 方法,需要处理什么写什么,View 不管如何实现,其只负责调用该回调方法。

至此,关于 Android 中的回调机制综述完毕。

本人才疏学浅,如有疏漏错误之处,望读者中有识之士不吝赐教,谢谢。

1
Email: [email protected] / WeChat: Wolverine623

您也可以关注我个人的微信公众号码农六哥第一时间获得博客的更新通知,或后台留言与我交流

参考文献

1.http://www.jianshu.com/p/3f86b7949f20

2.http://blog.csdn.net/xsf50717/article/details/50520462