Handler机制流程梳理、源码分析
在上几篇文章中我们已经介绍过了Android中使用线程、线程池以及异步任务的方法,通过对AsyncTask的源码分析,我们知道它的底层实现就是通过线程以及Handler机制来完成的,Handler机制也是Android提供的一种针对异步操作的方式,可以实现主线程与子线程之间的通信,接下来本篇文章就针对Android中的Handler机制进行解剖,总结。
Handler机制的相关类
首先我们看一下Handler的重载的构造方法,其中无参的构造方法又默认调用下面的这个构造方法。而这个构造方法中又做了那些事情呢?我们继续看,首先通过Looper.myLooper()初始化Looper对象mLooper,然后又初始化了MessageQueue对象mQueue。加上Handler发送的消息,整个Handler机制涉及到了如下几个类:
Handler、Looper、MessageQueue、Message
public Handler(Callback callback, boolean async) {
//前面省略
mLooper = Looper.myLooper();//获取Looper,**注意不是创建Looper**!
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;//创建消息队列MessageQueue
mCallback = callback; //初始化了回调接口
mAsynchronous = async;
}
那么这几个类的作用究竟是什么呢,他们之间又有什么关系,我们接下来继续看。
Looper与MessageQueue
使用过Handler的同学们知道,在主线程使用Handler的时候,并没有手动的创建Looper以及MessageQueue,实际上在主线程ActivityThread中,系统已经为我们创建了,源码如下,在ActivityThread的main方法中:
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
//其他代码省略...
Looper.prepareMainLooper(); //初始化Looper以及MessageQueue
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop(); //开始轮循操作
throw new RuntimeException("Main thread loop unexpectedly exited");
}
那么这几个方法中都做了些什么,我们接下来看一下。
Looper.prepareMainLooper():
这个方法主要是初始化Looper对象以及MessageQueue对象,首先执行了Looper的prepare(boolean quitAllowed)方法:
public static void prepareMainLooper() {
prepare(false);//
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
在这个方法中,首先判断了是否已经创建了Looper对象,没有的话就会调用Looper的构造方法,并set给sThreadLocal。
已经创建过得话,即if (sThreadLocal.get() != null)
,就会抛异常,这也体现了,一个线程里最多只能创建一个Looper对象以及一个MessageQueue(主线程已为我们创建好,而子线程默认没有)。
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
Looper与MessageQueue以及当前线程的绑定:
再看Looper的构造方法,在构造方法中创建了消息队列MessageQueue,并且绑定了当前的线程。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper.loop():
首先里面调用了sThreadLocal.get()获得刚才创建的Looper对象,后面进入一个死循环,从消息队列不断的取消息,如果有消息则交给Handler进行dispatchMessage,否则进入阻塞状态。
public static void loop() {
final Looper me = myLooper();//里面调用了sThreadLocal.get()获得刚才创建的Looper对象
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}//如果Looper为空则会抛出异常
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
//这是一个死循环,从消息队列不断的取消息
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);//msg.target就是绑定的Handler,详见后面Message的部分,Handler开始dispatchMessage(msg)
//后面代码省略.....
msg.recycleUnchecked();
}
}
Message
Message,即消息,实现了Parcelable接口,Message是怎么携带“消息内容”的呢?Message里面有4个变量,3个int型,what,arg1,arg2,以及一个Object型的变量obj,其中我们可以将需要传递的数据赋值obj,而在handleMessage方法中,就可以拿到我们所需要的数据进行处理了,而what可以作为一个标识符,来判断接收到的message对象里面存储的是什么数据类型,这样就可以针对不同的数据分别作出相应的操作了。
创建Message对象
为了发送消息,我们首先要获得Message对象,有些同学可能说了直接new一个出来就好了?实际上new出来也是可以的,但是有一种更好的方式。Message的获得由2种方式,一种是Handler的obtainMessage()方法,另一种是Message类的静态方法,Message.obtain()。
public final Message obtainMessage()
{
return Message.obtain(this);
}
通过看源码我们可以发现,Handler的obtainMessage()方法,内部就是调用了Message的obtain(Handler)方法,那么这么创建有什么好处呢?首先我们知道,直接通过new创建每次都会创建一个新的对象,这样不停的创建新的对象,会消耗资源。而使用Message.obtain()方法,第一次获取的时候,sPool为空,所以直接返回一个new Message()对象。
public static Message obtain(Handler h) {
Message m = obtain();//调用重载的obtain方法
m.target = h;//并绑定的创建Message对象的handler
return m;
}
public static Message obtain() {
synchronized (sPoolSync) {//sPoolSync是一个Object对象,用来同步保证线程安全
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
而在上面Looper的源码中,当handler进行dispatchMessage方法后,就会对message进行回收,这时候进入 recycleUnchecked()方法中,可以看到将使用过得message对象赋值给了sPool,这时候sPool就不为空了,而再次调用message.obtain()方法的时候,就避免了直接创建新的message对象,而是可以从回收的取出一个来进行复用。
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
因此在创建Message对象的时候,任何时候都推荐使用上面的2种方法,而不是直接使用new关键字来进行创建。
Message和Handler的绑定
通过这段代码,可以看到通过obtainMessage()创建的时候,就将Handler赋给了Message对象的target,完成了绑定。
public static Message obtain(Handler h) {
Message m = obtain();//调用重载的obtain方法
m.target = h;//并绑定的创建Message对象的handler
return m;
}
那么通过Message.obtain()这个无参的方法创建的Message对象,是怎么和Handler完成绑定的呢?
我们可以先看一段Handler的源码,在发送消息的时候,sendMessage通过一系列的调用,最终会调用enqueueMessage方法,在这里,就可以看到,发送的message即msg,在发送的时候,将this即hanlder对象与Message绑定到了一块。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;//将handler与message完成绑定
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
Handler
我们通过上面的源码,已经知道了Looper将Message对象从MessageQueue取出来,最终交给了Handler进行派发,下面我们来看一下Handler的源码,了解一下是怎么实现的。
Handler的构造方法:
在主线程通过无参的构造方法创建,而无参的构造方法调用重载的构造方法,并在此拿到了这个线程中对应的Looper以及MessageQueue,这样就完成了Handler与Looper、MessageQueue之间的绑定。
public Handler() {
this(null, false); //无参的构造方法调用重载的构造方法
}
public Handler(Callback callback, boolean async) {
//此处代码省略...
mLooper = Looper.myLooper();//拿到了当前线程的绑定的Looper
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;//拿到消息队列
mCallback = callback;
mAsynchronous = async;
}
Handler发送消息:
Handler发送消息的重载方法很多,但是主要只有2种。
- sendMessage(Message)
sendMessage方法通过一系列重载方法的调用,sendMessage调用sendMessageDelayed,继续调用sendMessageAtTime,继续调用enqueueMessage,继续调用messageQueue的enqueueMessage方法,将消息保存在了消息队列中,而最终由Looper取出,交给Handler的dispatchMessage进行处理。
我们可以看到在dispatchMessage方法中,message中callback是一个Runnable对象,如果callback不为空,则直接调用callback的run方法,否则判断mCallback是否为空,mCallback在Handler构造方法中初始化,在主线程通直接通过无参的构造方法new出来的为null,所以会直接执行后面的handleMessage()方法。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {//callback在message的构造方法中初始化或者使用handler.post(Runnable)时候才不为空
handleCallback(msg);
} else {
if (mCallback != null) {//mCallback是一个Callback对象,通过无参的构造方法创建出来的handler,该属性为null,此段不执行
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);//最终执行handleMessage方法
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
- post(Runnable)
post(Runnable)方法,实际上执行的是sendMessageDelayed方法,先将Runnable对象赋给了Message对象中的callback,然后通过sendMessage方法向下传递,中间过程同上面的相同,在dispacthMessage方法中,调用了handleCallback方法,在handleCallback方法中,最终执行Runnable对象的run()方法。
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();//将Runnable对象封装成Message对象
m.callback = r;
return m;
}
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);//sendMessage方法继续发送
}
public void dispatchMessage(Message msg) {
if (msg.callback != null) {//callback不为空,调用handleCallback方法
handleCallback(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();// message.callback即上面的post()中的Runnable对象,最终执行了run方法。
}
Handler处理消息:
在handleMessage(Message)方法中,我们可以拿到message对象,根据不同的需求进行处理,整个Handler机制的流程就结束了。