概述:
Handler是Android系统提供的异步消息通信机制,在程序开发中,经常用到Handler在不同的组件之间发送消息,不同的线程之间也可以利用Handler通信,在Handler通信中,包含3个重要部分Handler,Looper,MessageQueue。
Looper创建消息队列:
在日常开发中,我们经常在UI线程中创建一个Handler对象,然后重写其handleMessage方法,在其他线程或者组件可以利用该Handler往UI线程中发送异步消息,回调相关方法进行处理,那么其内部是怎样工作的呢?
下面我们将分析UI线程中消息通信机制的运作过程。
消息处理机制中,所有消息都是由Handler发送到Looper创建的消息队列,Looper对象不停从消息队列中获取消息,最后分发给Handler处理
那么问题来了:
1,UI线程的消息队列怎样创建,并且进入消息循环
2,Handler如何将消息发送到消息队列
3,Looper从消息队列取到消息后又是怎样处理。
先来看一下UI线程中消息队列的创建过程。大家都知道,Android启动一个新的应用程序,会创建一个新的进程,执行ActivityThread的main函数,创建Looper消息队列,并进入消息循环。同时还会创建一个Handler对象,绑定到UI线程的消息队列,在Activity生命周期中,onCreate,onPause等方法都是由该Handler对象往UI线程发消息,最后调起来的。
public final class Looper {
private static final String TAG = "Looper";
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
public static void prepare() {
prepare(true);
}
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));
}
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
/** Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the 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;
// 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);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycle();
}
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static Looper myLooper() {
return sThreadLocal.get();
}
public static MessageQueue myQueue() {
return myLooper().mQueue;
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
/**
* Return the Thread associated with this Looper.
*/
public Thread getThread() {
return mThread;
}
/** @hide */
public MessageQueue getQueue() {
return mQueue;
}
}
Looper类中sMainLooper即UI线程中的Looper对象,通过调用prepareMainLooper,最终会进入prepare函数,创建一个Looper对象,在Looper的构造函数中,创建一个消息队列。
调用loop()函数会进入消息循环,通过next函数获取消息,如果消息队列中没有消息,这里会阻塞,获取消息后通过msg.target.dispatchMessage(msg)将消息分发到Handler处理。
至此,UI线程中消息队列和循环的创建过程已经分析完毕,接下来我们再看Handler实现方式,Handler是怎样将消息发送到消息队列,以及从消息队列中取出消息后,Handler如何处理。
Handler:
public class Handler {
private static final boolean FIND_POTENTIAL_LEAKS = false;
private static final String TAG = "Handler";
public interface Callback {
public boolean handleMessage(Message msg);
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
public final Looper getLooper() {
return mLooper;
}
}
每个Handler对象必须关联一个Looper对象,Handler发送消息和接收消息都是基于这个Looper,Handler有多个构造函数,大致可以分为两类,含有Looper参数的和不含Looper参数的。含有Looper参数的构造函数,会使用参数传递的Looper对象,不含Looper参数使用当前线程中的Looper对象,如果线程没有创建一个Looper对象,则会抛出异常。
Handler关联一个Looper对象后,就可以往Looper对象创建的消息队列中发送消息,从源码来看,发送消息的方式有两种,一种是post,一种是send。
对于post方式,需要传入一个Runnable对象,这是一个回调对象,具体用途,在消息处理的时候再说,post传入runnable对象后,会调用gePostMessage方法构建一个msg,设置msg.callback为传入的runnable对象,最后调用send方式将消息发送到消息队列。所以,不管是post方法还是send方法,最后都是调用sendMessageAtTime,然后调用enqueueMessage方法,将消息放入到消息队列中。
消息发送到消息队列后,该如何处理呢。上面我们提到。Looper.loop()调用后,会不停的查询消息队列是否有消息,如果有,会调用msg.target.dispatchMessage()处理消息,msg.target即为发送该msg的Handler对象,dispatchMessage()方法中:
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
首先会判定msg.callback是否为空,这个msg.callback就是上面提到的post方式发送消息传入的Runnable对象,如果不为空,则调用handleCallback(msg); 这个函数里面会导致Runnable对象的run方法被调用。如果msg.callback为null,则判定mCallback是否为空,这个callback对象是Handler内部定义的接口,Handler构造函数可以传入一个Callback对象,如果Handler对象创建没有传入callback对象,那么mCallback为null,否则,调用该callback的handleMessage函数, 最后,调用Handler重写的handleMessage函数。整个过程可以用下面的时序图来表示。
上面分析了消息队列的创建与循环,Handler与Looper以及消息队列的关系,以及Handler如何发送和处理消息。可以用下面这个结构图来表示整个异步消息机制的运作流程
HandlerThread:
上面分析都是针对UI线程,如果我们想在自定义的线程中定义一个Handler,该怎么操作呢。
从上文分析可知,Handler对象必须依赖一个Looper对象,自定义线程中,并没有创建Looper对象。
有三种方式可以在自定义线程中创建Hander
1,使用带Looper对象的Handler构造函数,将主线程的Looper对象传入Handler构造函数中
Handler mHandler = new Handler(getMainLooper());
这种方式定义的Handler对象,使用了UI线程的消息队列,消息处理还是在UI线程中,和主线程中定义Handler,传入自定义线程没有任何区别。
2,自定义线程类,创建Looper对象,并且调用Looper.loop()方法开始消息循环。
3,使用HandlerThread类,这种方式其实就是第二种,只是Android系统已经帮我们做好了所有的工作,调用方便。
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
从HandlerThread的源码可以看到,实现方式和UI线程消息队列创建的方式类似,这里我们不再赘述。
HandlerThread类使用很简单:
HandlerThread ht = new HandlerThread("test");
Handler mHandler = new Handler(ht.getLooper());
mHandler.post(new Runnable() {
public void run(){
Log.e("HandlerThreadTest", "test handlerThread");
}
}
Handler消息通信机制是Android系统提供的非常重要的组件,开发中,应用非常广泛,我们不仅要知其然,还要知其所以然,只有这样,才能真正掌握其用法。
PS:文章如有错误,欢迎大家提出意见,一起讨论,共同进步~