Handler的用法网上有很多,这里主要分析其实现机制。
Handler相关的几个重要概念:Handler,Looper,Message,MessageQueue
Handler:用于线程间通信,与Looper关联,它负责向一个线程的消息队列里加入消息,或者接收Looper发送的消息并处理。
Message:消息,可以包含任意对象。
MessageQueue:消息队列,存放Message对象。
Looper:与一个Handler和一个线程关联,用于从线程的MessageQueue中循环获取Message并发送给Handler
=======================
回顾下Handler的简单用法:主线程中创建一个Handler,然后子线程调用其sendMessage方法发送消息,再从其handleMessage方法中接收消息。
handler = new Handler() { @Override public void handleMessage(Message msg) { textView.setText("11111111"); } }; send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(new Runnable() { @Override public void run() { Message msg = Message.obtain(); msg.what = 1; handler.sendMessage(msg); } }).start(); } });
先从Handler的构造方法开始分析:
public Handler() { this(null, false); } public Handler(Callback callback, boolean async) { ... mLooper = Looper.myLooper(); 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; }
mLooper = Looper.myLooper();
public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
sThreadLocal是一个ThreadLocal的全局变量:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
所以Looper.myLooper()返回的是当前线程关联的Looper对象。注意下面的if语句,如果mLooper对象为空,则抛出异常。对于主线程也就是UI线程来说,它在启动时就会和一个Looper是关联,所以不会返回null。主线程的启动流程:
先需要了解一个类ActivityThread:
/** * This manages the execution of the main thread in an * application process, scheduling and executing activities, * broadcasts, and other operations on it as the activity * manager requests. * * {@hide} */
这个类管理一个App主线程也就是我们所说的UI线程,它负责Activity的启动。
ActivityThread的入口函数main:
public static void main(String[] args) { ... Looper.prepareMainLooper(); ... Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }这里看到调用了Looper的静态方法prepareMainLooper,
Looper.prepareMainLooper():
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }
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.prepare方法中创建了一个Looper对象,并且保存到Looper的sThreadLocal这个ThreadLocal变量中。
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
Looper内部创建了一个MessageQueue对象赋值给mQueue对象,并且将当前线程赋值给mThread。
接下来看Handler构造方法的下一行代码:
mQueue = mLooper.mQueue;将Looper内部的MessageQueue对象赋值给全局变量mQueue
当我们需要用Handler发送消息时,会调用sendMessage系列方法,其中sendMessage方法的实现是:
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); }
可以看到内部调用了 enqueueMessage,并且将当前线程关联的MesssageQueque对象和发送的Message对象作为参数传入,那么看下 enqueueMessage:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
msg.target = this;这行将当前Handler赋值给Message的target变量。这个target变量作用是记录需要被回调handleMessage的Handler,接下来在MessageQueue的源码中会看到实现。
enqueueMessage:
boolean enqueueMessage(Message msg, long when) { if (msg.target == null) { throw new IllegalArgumentException("Message must have a target."); } if (msg.isInUse()) { throw new IllegalStateException(msg + " This message is already in use."); } synchronized (this) { ... Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; }
同步块里的语句作用是把Message对象放入MessageQueue中,通过Message.next来指定位置顺序。
通过阅读以上一系列代码,得出结论:
创建Handler时,Handler对象会和当前线程的Looper对象关联,Looper内部包含一个MessageQueue,Handler也引用了这个MessageQueue,Handler通过sendMessage方法发送的Message对象会插入这个MessageQueue当中。
接下来,当Handler在主线程中发送消息后,其handlerMessage方法如何被回调呢?答案就在Looper.loop方法中:
public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; ... for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } ... msg.target.dispatchMessage(msg); ... } }
首先通过myLooper获取当前线程关联的Looper,然后再获取Looper中的MessageQueue对象,for循环语句块是一个死循环,当MessageQueue中没有Message对象时会阻塞,一旦获取Message对象,会调用这个Message的target的dispatchMessage方法,target变量就是发送这个Message的Handler对象,target是在Handler的enqueueMessage方法中指定的。
可以在ActivityThread的main方法中看到,Looper.loop在最后被调用,所以对于主线程的Looper,会一直从MessageQueue中获取消息。
接下来看dispatchMessage:public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }如果handler没有设置callback的话,那么调用它的handleMessage方法。
通过阅读以上loop和dispatchMessage的代码,得出结论:Looper会一直从MessageQueue中取消息,并且调用当前消息关联的Handler的dispatchMessage。
以上代码分析是建立在主线程中创建Handler的情况上的,如果在子线程创建一个Handler,由于子线程没有创建Looper,所以在构造方法中调用Looper.myLooper()会返回null, mLooper对象为空,会抛出运行时异常:
new Thread(new Runnable() { @Override public void run() { handler = new Handler(); Message msg = Message.obtain(); msg.what = 1; handler.sendMessage(msg); } }).start();
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() at android.os.Handler.<init>(Handler.java:200) at android.os.Handler.<init>(Handler.java:114) at ohehehou.libtest.MainActivity$1$1.run(MainActivity.java:38) at java.lang.Thread.run(Thread.java:818)
所以,如果要在子线程中创建Handler并且向主线程发送消息,可以手动调用Looper.prepare来创建一个和子线程关联的Looper对象,并且还需要调用Looper.loop,这样Looper才能循环获取消息。
new Thread(new Runnable() { @Override public void run() { Looper.prepare(); handler = new Handler(); Message msg = Message.obtain(); msg.what = 1; handler.sendMessage(msg); Looper.loop(); } }).start();