版本:Android11
前言
Handler是Android中的非常重要的消息机制,能够在线程之间传递消息,例如Android主线程中的操作都是通过主线程的Handler进行的。最近在参加面试的时候有问到Handler相关的知识,才发自己对于这一块知识理解不深,好多问题都无法答的很好。所以准备查看一遍Framework中相关的内容,查缺补漏,让自己能够更好的理解Android Handler机制。
问题点
在看源码之前先整理一遍问题点,带着问题查看源代码效率更高。大家在看文章时也可以先看一遍问题,如果问题点上的知识全部都了如指掌,那么也没必要看这篇文章了。
- 什么是Looper?
- Looper、handler、线程间的关系,一个线程可以对应几个 Looper、几个Handler?
- 一个线程中有多个handler,它们发送消息是如何找到对应的handler的?
- 为何Handler会出现内存泄漏,其他内部类为什么没有这个问题?
- Handler是如何确保线程安全的?
源码解析
首先从主线程开始,我们知道在主线程中存在一个MianLooper,它会在我们的应用程序启动时创建,这里我们看ActivityThread的main方法,这个方法是我们Android应用程序的入口,具体关于ActivityThread的详细信息我们后续再进行讲解,目前我们专注于Looper
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
// Install selective syscall interception
AndroidOs.install();
// 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();
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
// Call per-process mainline module initialization.
initializeMainlineModules();
Process.setArgV0("<pre-initialized>");
//这里可以看到会调用MainLooper方法,来启动我们应用的主线程,也就是UI线程。
//后续应用中的消息调度,就都与它息息相关
Looper.prepareMainLooper();
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
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);
//这里调用loop方法之后,主线程的loop循环就正式启动了,并且只会在应用程序挂掉之后才会退出
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
这里可以看到,在每次启动一个应用程序的时候,会调用prepareMainLooper方法来启动一个主线程Looper,我们在子线程中使用过handler的都知道,要启动子线程Looper循环需要调用
Looper.prepare();
Looper.loop();
而prepareMainLooper方法就是主线程的prepare,后续再调用Looper.loop();之后,主线程的Looper循环就正式启动了。
接着我们来查看Looper中prepareMainLoope和prepare的实现,查看一下它们有什么差异
//这里是暴露给子线程使用的prepare,可以看到调用了一个私有的prepare方法并传入了一个true
public static void prepare() {
prepare(true);
}
//这个方法中主要做的事情便是将创建的Looper对象放入到sThreadLocal当中
//如果放入之前已经存在则会报错
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));
}
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. See also: {@link #prepare()}
*
* @deprecated The main looper for your application is created by the Android environment,
* so you should never need to call this function yourself.
*/
//这里是上文中提到的prepareMainLooper,这里同样调用了私有的prepare,并且传入了false
//底下则是判断一个静态常量,也就是代表主线程的sMainLooper ,如果已经存在,则抛出异常
@Deprecated
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
//私有的构造方法,除妖负责创建MessageQueue对象,以及获取当前的线程。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
通过查看Looper的初始化方法,我们可以发现一个线程中只允许存在一个Looper,当sThreadLocal中存在Looper对象时,再去调用prepare方法就会报出异常。
Looper中的初始化方法较为简单,里面并没有太多的代码,我们继续查看Looper中的loop方法
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
// 拿到当前线程的Looper对象
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
if (me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"
+ " before this one completed.");
}
me.mInLoop = true;
// 通过Looper对象获取MessageQueue
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();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
boolean slowDeliveryDetected = false;
for (;;) {
// 进入无限循环,开始通过MessageQueue的next方法
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
// 当拿到msg为空的时候,便会退出循环
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);
}
// Make sure the observer won't change while processing a transaction.
final Observer observer = sObserver;
final long traceTag = me.mTraceTag;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
Object token = null;
if (observer != null) {
token = observer.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try {
// 通过msg中的target对象将消息发送出去
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logSlowDelivery) {
if (slowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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();
}
}
代码较长,但是主要就做了几件事:
- 进入循环之前先拿到MessageQueue对象
- 通过MessageQueue 的next方法拿到队列中的msg
- 判断是否是msg是否为null,如果为null便退出循环
- 通过msg的target对象将消息发送出去
通过上面这几个步骤,便做到了消息的循环发送功能。看完上面这些代码,Looper的循环机制我们便弄清楚了,Looper会开启一个无限循环不停的获取消息,只有在msg为空时才会退出。不过看完上面这些代码,又会带出两个新的问题:
- 什么时候msg才会为空
- msg的target对象是怎么来的,为何通过它发送出去便能够发送到Handler中
一般子线程中的Looper,在使用完成之后都要进行退出,这也是为了代码性能的优化,带着上面的问题,我们继续查看Looper中的退出方法quit
// Looper 中的quit方法,直接调用到了MessageQueue中的quit方法
public void quit() {
mQueue.quit(false);
}
// MessageQueue中的quit方法
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
// 将mQuitting成员变量设置为true
mQuitting = true;
// 根据传入的参数,决定是直接移除所有消息还是等待消息发送完毕
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
// 调用native层的Wake方法
nativeWake(mPtr);
}
}
可以看到调用quit方法之后只是设置了mQuitting 为true,然后通过参数判定是否移除消息,最后是调用native层的唤醒方法,唤醒线程。在quit方法中,我们依然无法看出msg为何为空,所以我们继续往下看,找到MessageQueue的next方法
@UnsupportedAppUsage
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;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// native层方法,用于休眠线程,根据第二个参数的时间决定休眠时间
// -1表示是无限休眠,直到被手动唤醒
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.
// 如果msg.target为空,则移动到下一个非异步消息上
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
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.
// 时间不大于当前时间的情况下则取出消息给Looper
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.
// 当msg为空时,进行持续的休眠
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
// mQuitting变量在调用quit方法的时候会设置为true,此时便会返回一个null
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.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
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.
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);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
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;
}
}
此处代码也较长,但是关键的代码不多,大家配合注释应该能够看的明白,大概概括一下就是:拿到队列中头部的msg,判断设置的时间是否为当前时间,如果是当前时间小于设定的时间则进入休眠状态,否则将msg传递给Looper。后面判断当前是否调用了quit方法,调用了便返回null对象,退出整个Looper循环。
总结
到这一步,Looper便讲得差不多了,我们看到了这里,对于上面提出的Looper相关的问题答案也已经浮出水面。
Looper是一个线程内不断调用消息的循环,通过将构造方法私有化,并使用ThreadLocal存入当前线程的Looper对象来保证一个线程内只有一个Looper。
子线程内的Looper通过调用prepare方法对Looper初始化,调用loop方法进行循环,调用quit方法退出循环
其他的问题,待下一篇文章继续介绍Hanlder其他的内容我们再一一解决。