深入分析Android消息机制工作过程--Handler,Looper,MessageQueue
0.前言
image.pngHandler,Looper,MessageQueue三者配合共同完成Android的消息机制,每个线程都有自己的消息队列。消息机制是进程起来就会从android.app.ActivityThread#main方法为main主线程创建一个MessageQueue消息队列并通过Looper#loop方法进入不断从消息队列获取消息的过程。所以子线程需要自己添加一个线程队列。
1.Handler,MessageQueue,Looper三角关系
Handler:负责生产消息,接收消息。将消息post到消息队列MessageQueue中去。
Looper:负责循环从MessageQueue消息队列中获取消息,然后通过Handler分发消息出去各自处理。
MessageQueue:当前线程的消息队列,用于接受Handler post过来的消息,存储消息。
2.Handler工作过程分析
以下代码我们平时开发过程中应该非常熟悉,我们就从这里分析。
new Handler().post(new Runnable() { @Override public void run() { } });
首先我们从Handler post/postDelayed方法分析,具体这两个方法仅仅从消息池中获取一个消息实体,然后将Runnable类型r赋值给callback,用于后面回调。方法如下:
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }public final boolean postDelayed(Runnable r, long delayMillis) { return sendMessageDelayed(getPostMessage(r), delayMillis); }
我们可以看到post/postDelayed方法最终都是调用sendMessageDelayed方法。
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); }
通过以上代码queue.enqueueMessage(msg, uptimeMillis)可以看出,其实就是将一个消息加入到消息队列MessageQueue中。接下来我们继续跟进MessageQueue#enqueueMessage方法。
3.MessageQueue工作过程分析
首页我们看看MessageQueue这个消息队列是什么时候创建的。在这里我们大家平时开发过程中很少说到android程序的入口,学过C语言的同学应该知道程序的入口就是main方法,那android是不是也用main方法呢?同样也有,位于ActivityThread中main方法(android.app.ActivityThread#main)
public static void main(String[] args) { 。 。 。 Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } AsyncTask.init(); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
以上我们看到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(); } }
再跟进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)); }
我们看到sThreadLocal.set(new Looper(quitAllowed)),Looper构造方法如下:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
没错就是这里。然后我们跟进到Looper构造方法中,我们看到,原理MessageQueue是在Looper中初始化的。在这里我们看到sThreadLocal对象引用,这个其实就是一个本地变量副本,跟进ThreadLocal.set(new Looper(quitAllowed))方法你可以看到其实跟线程有关联了。这里就不赘述了。具体看我上篇:ThreadLocal分析。到这里其实我们应该可以知道每个线程都有自己的消息队列。
接着我们看看消息加入队列,源码如下:
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; }
4.Looper工作过程分析
首先我们从上面android.app.ActivityThread#main方法中我们可以看到,通过Looper.prepareMainLooper方法在Looper类中创建一个当前本地线程关联Looper对象并创建一个消息队列。然后通过Looper.loop方法不断的从消息队列中获取消息并通过Handler分发出对应的消息。下面我们重点看看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; // 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.recycleUnchecked(); } }
1.通过myLooper获取当前线程的Looper对象。
2.获取的myLooper不为空,这个时候取出Looper构造函数中创建的MessageQueue消息队列。
3.然后进入一个死循环中,通过queue.next取出下一个Message消息,消息为空则直接返回,反之继续执行。
4.通过dispatchMessage方法分发消息出去。这里我们看到是通过msg.target对象分发的,那msg.target是啥东西?我们看回android.os.Handler#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,这里我们知道msg.target其实就是一个Handler对象。
5.接着我们继续分析消息分发的过程,通过msg.target.dispatchMessage会调用android.os.Handler#dispatchMessage方法:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
当msg.callback不为空就调用handleCallback方法,msg.callback又是啥呢?我们回忆下android.os.Handler#getPostMessage(java.lang.Runnable)方法:
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
msg.callback其实是Handler#post方法的一个Runnable对象。
反之当msg.callback为空,同时mCallback不会空,就通过Callback接口回调到调用的地方,同时直接return。
public Handler(Looper looper, Callback callback) { this(looper, callback, false); }
通过上面可以看出mCallback是实例化Handler的时候传进来的,则消息就会回调到对应的handleMessage方法中。
到此整个消息机制的过程就分析完了。
That's All
更多相关文章
- APP开发实战61-Activity消息路由
- Android在真机调试的设置方法
- Android:ViewPage最详细的使用教程
- Android中实现ScrollView的滚动事件监听
- android 4.4以上实现沉浸式状态栏
- Android处理Home键方法小结
- View视图绘制流程,View工作原理(二)
- Alibaba-AndFix Bug热修复框架原理及源码解析
- Android(安卓)java.lang.UnsatisfiedLinkError: dalvik.system.P