Handler 作为 Android 消息通信的基础,它的使用是每一个开发者都必须掌握的。开发者从一开始就被告知必须在主线程中进行 UI 操作。但 Handler 是如何实现线程间通信的呢?本文将从源码中分析 Handler 的消息通信机制。
首先看看我们平时是如何使用的
的。先看看以下代码
- Handler
- //定义Handler
- Handler mHandler = new Handler(){
- public void handleMessage(Message msg){
- switch(msg.what){
- case UPDATE_UI:
- updateUI(msg);
- break;
- }
- }
- };
- class MyThread extends Thread{
- public void run(){
- //do same work!
- ...
- //send message
- Message msg = mHandler.obtainMessage(UPDATE_UI);
- mHandler.sendMessage(msg);
- }
- }
- private void updateUI(Message msg){
- //update UI
- }
在子线程中
发送消息,然后在 Handler 的
- sendMessage(Message)
接收消息,执行更新 UI 操作。那么
- handleMessage(Message)
是如何把消息从
- Handler
传递到
- MyThread
中来呢?我们从
- MainThread
开始慢慢揭开它的面纱。
- 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);
- }
- ...
- private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
- msg.target = this;
- if (mAsynchronous) {
- msg.setAsynchronous(true);
- }
- return queue.enqueueMessage(msg, uptimeMillis);
- }
我们发现调用
方法最后都走到
- sendMessage()
这个方法,一开始就把当前
- enqueueMessage()
实例赋给了
- Handler
的属性里面,后面可以知道这个
- Message.target
是用来执行处理函数回调的。
- target
方法是把
- enqueueMessage
信息放入到一个
- Message
的队列中。顾名思义
- MessageQueue
就是消息队列。从
- MessageQueue
方法知道这个
- sendMessageAtTime()
是
- MessageQueue
中的一个成员。它是在
- Handler
的构造函数中通过
- Handler
对象来初始化的。
- Loopger
- public Handler(Callback callback, boolean async) {
- if (FIND_POTENTIAL_LEAKS) {
- final Class klass = getClass();
- if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
- (klass.getModifiers() & Modifier.STATIC) == 0) {
- Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
- klass.getCanonicalName());
- }
- }
- 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;
- }
这时候我们脑海知道创建
的时候,同时也创建了
- Handler
实例和
- Looper
引用(
- MessageQueue
对象其实是在
- MessageQueue
中构造的)。
- Looper
是何物呢?简单地说就是消息循环,这个我们稍后会分析。
- Looper
- 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) {
- if (mQuitting) {
- IllegalStateException e = new IllegalStateException(
- msg.target + " sending message to a Handler on a dead thread");
- Log.w(TAG, e.getMessage(), e);
- msg.recycle();
- return false;
- }
- msg.markInUse();
- msg.when = when;
- 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;
- }
在
中可以看到这个入列方法中有一个
- MessageQueue
循环就是把当前的需要处理
- for
放到队列的合适位置。因为需要处理的
- Message
对象都有一个开始处理的时间
- Message
,这个队列是按照
- when
排序的。
- when
至此,
调用
- Handler
方法后就把
- sendMessage()
消息通过
- Message
插入
- enqueueMessage()
队列中。
- MessageQueue
而这个
是在
- MessageQueue
中维护的。
- Looper
在 0x02 中我们知道创建
时就使用静态方法
- Handler
得到当前线程的
- Looper.myLooper()
对象。
- Looper
- /**
- * Return the Looper object associated with the current thread. Returns
- * null if the calling thread is not associated with a Looper.
- */
- public static @Nullable Looper myLooper() {
- return sThreadLocal.get();
- }
是一个
- sThreadLocal
类型的静态变量。什么时候会把
- ThreadLocal
对象放在
- Looper
中呢?通过
- sThreadLocal
方法。
- prepare()
- 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
- private Looper(boolean quitAllowed) {
- mQueue = new MessageQueue(quitAllowed);
- mThread = Thread.currentThread();
- }
调用
方法将一个
- prepare()
对象放在了静态的
- Looper
对象中。这个是一个与线程绑定的对象,且在内存中仅保存了一份引用。
- ThreadLocal
使用
对象这一点非常巧妙,也非常重要,这是线程间通信的基础。即在线程中调用
- ThreadLocal
时就在该线程中绑定了
- prepare()
对象,而
- Looper
对象中拥有
- Looper
引用。所以每个线程都有一个消息队列。
- MessageQueue
这样
、
- Handler
、
- Looper
这几个类关系大概就可以画出来了。
- MessageQueue
- /**
- * 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
- final Printer logging = me.mLogging;
- if (logging != null) {
- logging.println(">>>>> Dispatching to " + msg.target + " " +
- msg.callback + ": " + msg.what);
- }
- final long traceTag = me.mTraceTag;
- if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
- Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
- }
- //执行处理消息的回调
- try {
- msg.target.dispatchMessage(msg);
- } finally {
- if (traceTag != 0) {
- Trace.traceEnd(traceTag);
- }
- }
- 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.recycleUnchecked();
- }
- }
方法中有一个无限循环,不停地读取调用
- loop()
的
- MessageQueue
方法。当
- next()
没有返回时就阻塞在这里。当获取到
- next()
中的消息时,就执行了处理消息的回调函数
- MessageQueue
。
- msg.target.dispatchMessage(msg)
前面 0x01 分析我们知道
是在
- msg.target
中的
- Handler
进行赋值,即它指向当前的
- enqueueMessage()
实例。
- Handler
- private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
- msg.target = this;
- if (mAsynchronous) {
- msg.setAsynchronous(true);
- }
- return queue.enqueueMessage(msg, uptimeMillis);
- }
执行
后便走到了以下流程
- msg.target.dispatchMessage(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);
- }
- }
这里就是回调
函数处理消息的地方。
- handleMessage(msg)
负责将
- Handler
入列,
- Message
则负责循环从
- Looper
中取出需要处理的
- MessageQueue
并交由 Handler 来处理。
- Message
我们知道通过静态方法
创建了绑定当前线程的
- Looper.prepare()
对象,而通过
- Looper
启动一个循环不停地读取队列中
- loop()
。但是 Android 系统是什么时候启动了主线程的消息循环呢?
- Message
要理解这一点就必须进入 Android 应用程序的入口
的
- ActivityThread
方法。
- main
- public static void main(String[] args) {
- ...
- Looper.prepareMainLooper();
- ...
- Looper.loop();
- throw new RuntimeException("Main thread loop unexpectedly exited");
- }
可以看出
方法中先后执行了
- main
方法和
- Looper.prepareMainLooper()
方法。正常情况下
- Looper.loop()
方法不会退出,只有
- main
方法发生异常后将会抛出
- loop()
。
- RuntimeException
- /**
- * Initialize the current thread as a looper, marking it as an
- * application's main looper. The main looper for your application
- * is created by the Android environment, so you should never need
- * to call this function yourself. See also: {@link #prepare()}
- */
- public static void prepareMainLooper() {
- prepare(false);
- synchronized (Looper.class) {
- if (sMainLooper != null) {
- throw new IllegalStateException("The main Looper has already been prepared.");
- }
- sMainLooper = myLooper();
- }
- }
方法其实是调用了
- prepareMainLooper()
方法。
- prepare()
当我们启动应用时系统就调用了
并在主线程中绑定了一个
- prepareMainLooper()
对象。
- Looper
这时候我们回过来看看一开始的
使用方式。在主线程中我们创建了
- Handler
对象,在
- Handler
构造函数中初始化了
- Handler
(即获取到了绑定在主线程中的
- Looper
对象)。当在子线程
- Looper
中通过
- MyThread
方法发送一个消息时就把
- mHandler.sendMessage(msg)
放在与主线程绑定的
- Message
中。这样在子线程中使用
- MessageQueue
就实现了消息的通信。
- Handler
可以简单的使用以下类图表示,每个线程都由一个 Handler,每个 Handler 都是与当前所在线程的 Looper 绑定。
在 0x06 中知道在
的
- ActivityThead
方法中启动了一个死循环。那主线程是不是就一直阻塞在这里呢?其实不然。可以看到
- main
类里面有一个自定义的
- ActivityThread
对象
- Handler
,在这里对象中
- mH
回调中定义了
- handleMessage()
的各种交互如管理
- Activity
生命周期,启动
- Activity
,显示
- service
等,都是通过
- window
进行处理的。同时可以看出只有当应用退出
- Handler
之后才回调用
- EXIT_APPLICATION
停止消息循环。
- Looper.quit()
- public void handleMessage(Message msg) {
- ...
- switch (msg.what) {
- case LAUNCH_ACTIVITY: {
- ...
- handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- } break;
- ...
- case PAUSE_ACTIVITY: {
- ...
- handlePauseActivity((IBinder) args.arg1, false,
- (args.argi1 & USER_LEAVING) != 0, args.argi2,
- (args.argi1 & DONT_REPORT) != 0, args.argi3);
- ...
- } break;
- ...
- case SHOW_WINDOW:
- ...
- handleWindowVisibility((IBinder)msg.obj, true);
- ...
- break;
- ...
- case EXIT_APPLICATION:
- if (mInitialApplication != null) {
- mInitialApplication.onTerminate();
- }
- Looper.myLooper().quit();
- break;
- ...
- }
- ...
- }
当创建
时将通过
- Handler
在当前线程绑定一个
- ThreadLocal
对象,而
- Looper
持有
- Looper
对象。执行
- MessageQueue
方法将一个待处理的
- Handler.sendMessage(Message)
插入到
- Message
中,这时候通过
- MessageQueue
方法获取到队列中
- Looper.loop()
,然后再交由
- Message
来处理。
- Handler.handleMessage(Message)
- 微信关注我们,可以获取更多
来源: http://www.cnblogs.com/angrycode/p/6576905.html