Android Handler消息机制源码解读
Posted 瞌睡先生想睡觉
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Handler消息机制源码解读相关的知识,希望对你有一定的参考价值。
这个东西在网上已经被很多人写过了,自己也看过很多文章,大概因为自己比较愚笨一直对此不太理解,最近重新从源码的角度阅读,并且配合着网上的一些相关博客才算明白了一些
本文从源码的角度顺着代码的执行去源码,限于作者的表达能力及技术水平,可能会有些问题,请耐心阅读,如有不解或有误的地方欢迎提出
从ActivityThread的入口去看
ActivityThread.class
public static void main(String[] args)
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
//这里创建了属于线程的Looper对象
Looper.prepareMainLooper();
//这里创建了ActivityThread对象,随之一起初始化的还有一个用于处理相应消息的Handler对象
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");
这里是App的入口,有着我们非常熟悉的main方法,
Looper.prepareMainLooper();这个方法创建了属于主线程的Looper对象,并且将其放到了ThreadLocal中,再在Looper.loop();中取出Looper对象开启循环
看下Looper.prepareMainLooper();方法的源码
Looper.class
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
private Looper(boolean quitAllowed)
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
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();
public static @Nullable Looper myLooper()
return sThreadLocal.get();
prepareMainLooper()方法首先调用了prepare(false)方法,传入的quitAllowed参数的意思是是否允许退出循环,主线是不允许的,其他的都是允许退出的,prepare方法首先要从sThreadLocal中get()一下判断当前线程中是否已经有过Looper对象,如果已经有了就无法重复创建,如果没有就初始化Looper对象然后放到sThreadLocal中去,sThreadLocal这个变量是ThreadLocal类型的,ThreadLocal这个类是用来存储线程内的本地变量,或者是说,当前线程可以访问的全局变量,有兴趣可以了解下源码,这里就不说了.
Looper初始化的方法是私有的,所以只能通过prepare方法去创建,Looper初始化的时候顺便初始化了MessageQueue对象和获取了mThread这个当前线程的对象.然后prepare方法执行完成之后prepareMainLooper()方法还判断了sMainLooper是否为空然后调用myLooper()方法取出放到sThreadLocal 中的Looper对象赋值给sMainLooper对象
所以根据上面的代码能得出结论,一个线程只有一个Looper对象,Looper对象中有一个MessageQueue对象
接下来看下Looper.loop()方法的源码:
Looper.class
/**
* 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 slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag))
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
final long end;
try
//分配给Message所对应的Handler处理
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
finally
if (traceTag != 0)
Trace.traceEnd(traceTag);
if (slowDispatchThresholdMs > 0)
final long time = end - start;
if (time > slowDispatchThresholdMs)
Slog.w(TAG, "Dispatch took " + time + "ms on "
+ Thread.currentThread().getName() + ", h=" +
msg.target + " cb=" + msg.callback + " msg=" + msg.what);
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方法首先调用myLooper()方法来获取当前线程存放在sThreadLocal中的Looper对象,然后进行一下非空判断,在获取到对应的
MessageQueue对象.然后来看关键代码:Message msg = queue.next(); 这句代码就是从消息队列里面取出消息,然后msg.target.dispatchMessage(msg);去分配给相应的Handler处理,msg.target是Message对应的Handler.
然后在调用msg.recycleUnchecked();对Message对象进行回收,等待再利用,如果next()取出的消息为空就退出循环
接下来看queue.next();方法是如何将消息取出来的
MessageQueue.class
// True if the message queue can be quit.
//是否允许退出,在初始化MessageQueue的时候传入赋值
private final boolean mQuitAllowed;
@SuppressWarnings("unused")
//这个属性是有关底层c相关的东西,因为C相关的我也不会所以更底层的代码也没看过,但是不影响去理解这个消息机制
private long mPtr; // used by native code
//消息队列
Message mMessages;
//空闲时执行的代码
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
private IdleHandler[] mPendingIdleHandlers;
//是否退出
private boolean mQuitting;
// Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
//是否阻塞
private boolean mBlocked;
MessageQueue(boolean quitAllowed)
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
Message next()
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0)
return null;
//这个值用于控制IdleHandler是否被执行
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;)
if (nextPollTimeoutMillis != 0)
Binder.flushPendingCommands();
//这个是主要的阻塞方法,当消息队列中没有时间或者需要执行的消息没到执行时间,就会阻塞,更底层是涉及到Linux的一些东西,我也不甚了解
//nextPollTimeoutMillis这个参数是阻塞时间
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this)
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null)
//什么时候会进入到这个循环中,这一点我在后面再去说这个逻辑
// Stalled by a barrier. Find the next asynchronous message in the queue.
do
//记录当前消息,并获取下一条异步消息
prevMsg = msg;
msg = msg.next;
while (msg != null && !msg.isAsynchronous());
//如果msg不为空
if (msg != null)
//判断是否到执行时间,如果时间没到就算出差值,线程等待
if (now < msg.when)
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
else
//可以执行取出消息返回
// Got a message.
mBlocked = false;
if (prevMsg != null)
prevMsg.next = msg.next;
else
mMessages = msg.next;
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
else
// No more messages.
//没有消息为-1,无期限等待,直到有新消息唤醒
nextPollTimeoutMillis = -1;
// Process the quit message now that all pending messages have been handled.
//退出循环
if (mQuitting)
dispose();
return null;
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
//只有在上面没有取到合适的消息的时候才会执行到这一步,判断pendingIdleHandlerCount是否小于0,只有小于0才会赋值,
//小于0的情况只有在调用next方法进来的时候在循环体外面初始化
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when))
pendingIdleHandlerCount = mIdleHandlers.size();
//经过上面的赋值,如果pendingIdleHandlerCount值小于等于0就不会执行下面的mIdleHandlers的相关代码
if (pendingIdleHandlerCount <= 0)
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
if (mPendingIdleHandlers == null)
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
//循环遍历IdleHandler并执行,这里的代码只有在没有Message的时候才会执行
for (int i = 0; i < pendingIdleHandlerCount; i++)
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try
//执行接口代码,并且获取返回值判断是不移除⊙﹏⊙
keep = idler.queueIdle();
catch (Throwable t)
Log.wtf(TAG, "IdleHandler threw exception", t);
//false就会删除掉
if (!keep)
synchronized (this)
mIdleHandlers.remove(idler);
// Reset the idle handler count to 0 so we do not run them again.
//这个参数赋值为0,就不会被重新赋值,所以没调用一次next方法,IdleHandler中的代码最多只会执行一次
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
至此循环去消息的代码的逻辑差不多就这些,每次循环都会从MessageQueue中的Message中取出消息,Message不仅仅是消息的载体,它还是一个单链表结构,中间有一个next属性指向下一个Message.还有就是mIdleHandlers,这个是用来在空闲时间,即在没有取到合适执行的Message的时候回去检测调用执行的代码,并且每次next只会执行一次,使用方法如下:
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler()
@Override
public boolean queueIdle()
//do something
return false;
);
下面来从Handler入口来看下怎么把消息放到消息队列当中去
Handler handler = new Handler(new Handler.Callback()
@Override
public boolean handleMessage(Message msg)
return false;
);
handler.sendMessage(Message.obtain());
从Handler的初始化来引入:
Handler.calss
final Looper mLooper;//Loper对象,如果不传入则默认是本线程的Looper对象,如果为空则抛异常
final MessageQueue mQueue;
final Callback mCallback;
final boolean mAsynchronous;//是否异步,默认为false
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)
this(looper, callback, false);
public Handler(boolean async)
this(null, async);
public Handler(Callback callback, boolean async)
if (FIND_POTENTIAL_LEAKS)
final Class<? extends Handler> 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;
public Handler(Looper looper, Callback callback, boolean async)
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
在这里可以看到,初始化的方法最终都是给Handler中的变量赋值
接下来是sendMessage方法:
Handler.class
public final boolean sendMessage(Message msg)
return sendMessageDelayed(msg, 0);
...
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
msg.target = this;
if (mAsynchronous)
msg.setAsynchronous(true);
return queue.enqueueMessage(msg, uptimeMillis);
sendMessage方法有很多重载的我就不都贴出了,但是他们最终调用的都是enqueueMessage方法,这个方法将Message绑定了当前的Handler,给Message设置了在Handler初始化的时候初始化的mAsynchronous参数,以及调用了MessageQueue对象的enqueueMessage方法,将Message对象和消息执行时间传入
enqueueMessage方法源码:
MessageQueue.class
boolean enqueueMessage(Message msg, long when)
//判断Message绑定的Handler是否为空
if (msg.target == null)
throw new IllegalArgumentException("Message must have a target.");
//判断Message是否在使用中
if (msg.isInUse())
throw new IllegalStateException(msg + " This message is already in use.");
//同步代码块
synchronized (this)
//退出就回收Message,返回true
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队列
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;
这样插入的代码也就说完了,整个流程的逻辑就是
Handler发送Message到MessageQueue中,然后Looper不断的循环从MessageQueue中取出Message再分配给相应的Handler执行
Looper: 负责不停的从MessageQueue中取出Message并且分配给Handler执行
MessageQueue: 负责Message队列的读和写
Handler: Handler负责向MessageQueue中发送Message并且处理Message
Meessage: 消息载体
接下来看看前文中提到的一些方法:
在Looper中有调用的Handler.dispatchMessage()方法是怎么处理消息的
Handler.class:
final Callback mCallback;
//这个方法负责处理Message
public void dispatchMessage(Message msg)
//首先判断Message的 Runnable callback 是否为空
if (msg.callback != null)
//不为空就执行callback的run方法
handleCallback(msg);
else
//然后判断mCallback是否为空,如果不为空就交给mCallback处理
if (mCallback != null)
if (mCallback.handleMessage(msg))
return;
//如果上面两个条件都不成立才调用本类的handleMessage方法
handleMessage(msg);
private static void handleCallback(Message message)
message.callback.run();
再来看下Message的消息回收机制
关于obtain方法,这个方法是用来获取一个Message的,有很多重载的,我们只看最关键的
Message.class
private static Message sPool;//Message用来放置被回收的Message
private static int sPoolSize = 0;//当前sPool中消息的数量
private static final int MAX_POOL_SIZE = 50;//sPool内最大的消息的数量
public static Message obtain()
//同步代码块
synchronized (sPoolSync)
if (sPool != null)
//取出队列中的消息并返回
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
//如果sPool中没有Message就新建一个并返回
return new Message();
public void recycle()
//正在使用的方法不允许回收
if (isInUse())
if (gCheckRecycle)
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
return;
recycleUnchecked();
void recycleUnchecked()
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
//将消息标记为正在使用状态,然后清空其他的Message所附带的消息
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)
//如果sPoolSize还没到最大值就将消息放到sPool中去
if (sPoolSize < MAX_POOL_SIZE)
next = sPool;
sPool = this;
sPoolSize++;
然后现在我们在回头看下Message异步的事情
Message.class 中有一个flags字段,是用来记录Message的是否正在使用中和消息是否异步的
/*package*/ int flags;
public boolean isAsynchronous()
return (flags & FLAG_ASYNCHRONOUS) != 0;
public void setAsynchronous(boolean async)
if (async)
flags |= FLAG_ASYNCHRONOUS;
else
flags &= ~FLAG_ASYNCHRONOUS;
/*package*/ boolean isInUse()
return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
/*package*/ void markInUse()
flags |= FLAG_IN_USE;
是否正在使用中就不说了,下面主要来看看Message的Asynchronous的作用,根据上面的逻辑在一般情况下Message的Asynchronous的状态并不影响消息的分发机制,不过一旦遇到了msg的target为null的情况就会有影响,上面我们也看过了,在sendMessage的时候都会去绑定Handler那么什么时候出现target为null的情况呢,就是在调用了postSyncBarrier方法之后,这个方法在MessageQueue中,添加的这个特殊消息的主要作用就是在在遇到这个消息之后的同步Message都不会取到执行,异步Message还是会继续取出来执行这也是同步Message和异步Message的区别
if (msg != null && msg.target == null)
// 在这里遇到这个同步障碍之后只会取异步消息
do
prevMsg = msg;
msg = msg.next;
while (msg != null && !msg.isAsynchronous());
相关代码
public int postSyncBarrier()
return postSyncBarrier(SystemClock.uptimeMillis());
private int postSyncBarrier(long when)
// Enqueue a new sync barrier token.
// We don't need to wake the queue because the purpose of a barrier is to stall it.
synchronized (this)
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
//找合适的位置插入
Message prev = null;
Message p = mMessages;
if (when != 0)
while (p != null && p.when <= when)
prev = p;
p = p.next;
if (prev != null) // invariant: p == prev.next
msg.next = p;
prev.next = msg;
else
msg.next = p;
mMessages = msg;
return token;
public void removeSyncBarrier(int token)
// Remove a sync barrier token from the queue.
// If the queue is no longer stalled by a barrier then wake it.
synchronized (this)
Message prev = null;
Message p = mMessages;
//找到SyncBarrier
while (p != null && (p.target != null || p.arg1 != token))
prev = p;
p = p.next;
if (p == null)
throw new IllegalStateException("The specified message queue synchronization "
+ " barrier token has not been posted or has already been removed.");
final boolean needWake;
if (prev != null)
//如果在SyncBarrier之前还有消息就不用唤醒
prev.next = p.next;
needWake = false;
else
//如果SyncBarrier是第一个Message
mMessages = p.next;
//如果SyncBarrier移除后第一个消息是空,或者绑定的Handler不为空,也就是说移除后的消息不再是SyncBarrier也要唤醒
needWake = mMessages == null || mMessages.target != null;
p.recycleUnchecked();
// If the loop is quitting then it is already awake.
// We can assume mPtr != 0 when mQuitting is false.
if (needWake && !mQuitting)
//需要唤醒且队列没有正在退出就唤醒
nativeWake(mPtr);
最后在多说一句,阅读源码真的是一个让人进步的有效方式,在过程中如果有不了解的可以去网上找一些别人阅读源码的文章,对自己帮助很大,有时候感觉实在读不下去,我都是硬着头皮去看(╥﹏╥)
以上是关于Android Handler消息机制源码解读的主要内容,如果未能解决你的问题,请参考以下文章
深入理解Android Handler机制(深入至native层)
深入理解Android Handler机制(深入至native层)
Android Handler消息机制02-Looper源码学习