Handler、Looper源码学习
Android中,使用Handler,Looper的场景主要是跨线程通信,先看一个简单的例子:
public class MainActivity extends Activity {
public final static int MESSAGE_TYPE_1 = 1;
private WorkHandler mHandler;
private static class WorkHandler extends Handler {
public WorkHandler(Looper looper) {
super(looper);
}
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_TYPE_1:
LogUtils.d("this is message 1");
// do something...
break;
default:
break;
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
HandlerThread thread = new HandlerThread("work_thread"); // 创建一个线程对象
thread.start(); // 启动子线程,这时会利用HandlerThread#run方法,创建一个Looper对象,绑定子线程,线程的执行并进入loop循环模式
mHandler = new WorkHandler(thread.getLooper()); // 创建一个Handler对象,并传入Looper
Message msg = new Message();
msg.what = MESSAGE_TYPE_1;
mHandler.sendMessage(msg); // 通过主线程发送1个消息,消息被压入messageQueue(所属于Looper对象)
}
}
这里涉及到4个重要的类:Handler,Looper,MessageQueue(Handler和Looper的成员变量),HandlerThread。
1. Handler
public class Handler {
final Looper mLooper;
final MessageQueue mQueue;
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
// ...
}
}
Handler类有2个成员变量,mLooper和mQueue,从构造函数可看出,mQueue用的也是Looper的成员变量。所以本质上Handler含有1个Looper对象。
Handler有2个重要的方法,我们经常用到,sendMessage和handleMessage。
- sendMessage的真正实现是enqueueMessage方法,如下:
将一条新消息Message压入MessageQueue对象(即mQueue,所属于mLooper),默认是同步,Handler初始化时可设置消息发送是否异步private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; // 重要步骤1. 将此Handler对象绑定到此Message对象,以便将来Looper.loop方法中调用目标Handler对象来处理此消息 if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
- handleMessage是处理消息的函数,由dispatchMessage方法所调用,一般应用使用时重写handleMessage函数,定制自己的消息处理逻辑
2. Looper
Looper类有2个重要的成员变量,mQueue和mThread,另外还有1个所属于进程的sThreadLocal集合,ThreadLocal<Looper>本质是一个Map数据结构,key是线程对象,value是Looper对象。它的作用是保存进程中所有<Thread,Looper>的信息,保证Looper对象和线程1:1对应。
public final class Looper {
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
final MessageQueue mQueue;
final Thread mThread;
// ...
}
Looper有3个重要的静态方法:prepare,prepareMainLooper,loop。
- prepare方法是为本线程创建一个Looper对象,并插入sThreadLocal中保存
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thLooper.prepare,Looper.loop等read");
}
sThreadLocal.set(new Looper(quitAllowed));
}
- prepareMainLooper方法是给ActivityThread#main方法调用的,进程启动时最先执行的入口函数里,完成主线程Looper的初始化。因为时机是最早的,如果应用在启动完成后,再调用此方法,会抛出异常
public static void prepareMainLooper() {
prepare(false); // false代表参数quitAllowed的值,表示不允许退出
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
- loop方法的核心是一个无限循环,不断从mQueue中取出新消息,调用目标Handler#dispatchMessage方法来处理消息,其中dispatchMessage里就会调用Handler#handleMessage方法
public static void loop() {
// ...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// ...
msg.target.dispatchMessage(msg);
// ...
}
}
3. MessageQueue
MessageQueue的实现较为复杂,主要是利用JNI,调用native相关方法,例如MessageQueue初始化时,调用nativeInit();
代码路径:frameworks/base/core/jni/android_os_MessageQueue.cpp
这里暂时先不深入研究,后面再补充。
4. HandlerThread
HandlerThread的实现很简单,继承于Thread类。作用是封装一个默认带Looper的Thread类,省去开发者自己调用Looper.prepare,Looper.loop等方法,使Handler的使用更方便。如本文开始的例子。
HandlerThread的核心方法是重写的run方法,其中会调用Looper.prepare,Looper.loop等。
总结:
- 1条消息的生命周期总结如下,简单分为3步:
handler.sendMessage(msg) --线程A发送消息,消息压入messageQueue----> looper.loop --线程B从messageQueue中取出消息----> handler.handleMessage(msg)--线程B消费掉此消息----> 结束 - Handler,Looper,MessageQueue,从对象角度所属的关系:
handler <----- looper <----- messageQueue - Looper#quit和Looper#quitSafely方法有何区别?
a. Looper#quit -> mQueue#quit(false) -> mQueue#removeAllMessagesLocked
直接终止Looper,不再处理所有消息
b. Looper#quitSafely -> mQueue#quit(true) -> mQueue#removeAllFutureMessagesLocked
处理完MessageQueue中已有消息,再终止Looper
作者:kevin song,2018.11.20于南京建邺区
上一篇: 源码解析 Handler机制
下一篇: Andorid Handler源码解析