Android 中,使用 AsyncTask 来执行简单的后台线程,但是 AsyncTask 较适用于短暂的、不重复的运行任务。因为从 Android 3.2 起,AsyncTask 不再为每个实例创建线程,而是利用一个 Executor 在单一的后台线程上运行所有的 AsyncTask 后台任务,相当于所有的 AsyncTask 实例在同一个队列中排队运行,所以长时间且重复运行的 AsyncTask 会影响其他实例的运行,导致堵塞。实现按需下载的等后台运行方式,通常会使用到 HandlerThread。
消息
首先介绍一下消息(Message),消息是 Message 类的实例,携带着需要处理的各种任务信息。有以下几个常见变量:
-
what:用户定义的 int 型消息代码,用来描述和识别信息;
-
obj:随消息发送的用户指定对象;
-
target:处理消息的 Handler,创建 Message 时会自动与一个 Handler 关联,通常不用手动设置;
-
arg1、arg2:随消息返回的两个 int 类型参数。
Handler
Handler 作为 Message 的目标,除了用来触发 message 的处理事件,也是创建和发布 Message 的接口。message 是 在Handler.handleMessage(Message) 方法中进行处理的。
Looper 和 Message、Handler 的关系
Android 的消息循环(message loop)由线程和 looper 组成。Looper 对象管理着消息队列(meesage queue),消息队列中存放着许多的消息(message),它们与 handler 相关联。为了与 Looper 协同工作,Handler 总是引用着 Looper。**主进程本身就是一个拥有 handler 和 Looper 的消息循环,**在主线程中 Android 默认已经调用了 Looper.prepare() 方法,调用该方法的目的是在 Looper 中创建 MessageQueue 成员变量并把 Looper 对象绑定到当前线程中。
- 一个 Message 只和一个目标 Handler 相关联,但是多个 Message 能引用同一个目标Handler。
**
**
- 一个 Handler 只和一个 Looper 相关联,但是多个 Handler 可以与一个 Looper 相关联。所以消息队列中可能存放着来自不同 Handler 的 Message。(如下图二)
创建 Message 并关联 Handler
如果有一个类继承了 HandlerThread,那么 Handler 可以在函数 onLooperPrepared() 中新建,因为该函数是在 Looper 首次检查消息队列之前调用的。一般会在 new 一个 Handler 的同时覆写其 handleMessage(Message) 方法。
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
//TODO
}
}
};
消息的发送可以有以下几种:
-
使用 Handler.obtainMessage(Message) 方法来创建信息,此时可以将消息自动设置目标为该 Handler 对象,取得 Message 之后可以使用 sendToTarget 发送给 Handler。Handler 会把该 Message 放置在 MessageQueue 消息队列尾部。
Message mMessage = mHandler.obtainMessage(...); mMessage.sendToTarget();
-
使用 Handler.sendMessage(Message) 方法:
mHandler.sendMessage(message);
-
也可以使用 Handler.post(Runnable) 方式来发送消息:
mHandler.post(new Runnable() { @Override public void run() { //TODO } });
看看源码会发现它是把 Runnable 转换成了一条空的 message,设置它的私有变量 callback 为我们传入的 Runnable,然后再调用 sendMessageDelayed(Message) 方法的。
当 message 设有回调方法时,它从消息队列取出后,是不会发给 target Handler 的,而是直接执行存储在 callback 中的 Runnable 的 run() 方法。