我们都知道平时在子线程要刷新UI线程的时候一般会用
runOnUiThread(new Runnable() { @Override public void run() { } });
或者 handler.post(new Runnable(){
});
那么Handler机制是怎么实现跨线程通信的呢?提到Handler其实他就像是一个机制对外开放的API,实际的核心实现是Looper、Thread、MessageQueue。那么我们先来了解Looper
首先 Looper 像是一条流水线,一直在不停的检查消息队列。MassageQueue是以链表结构存储的消息队列,遵循先进先出。
//Looper 持有了Thread和MessageQueue
public final class Looper {
private Looper(boolean quitAllowed) { //Looper创建的时候就绑定了一个线程和一个消息队列 mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
public static void loop() {//loop方法在不停的检查消息队列 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; // 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); me.mSlowDeliveryDetected = false; for (;;) {//for死循环不停的检查队列 if (!loopOnce(me, ident, thresholdOverride)) { return; } } }
private static boolean loopOnce(final Looper me, final long ident, final int thresholdOverride) { Message msg = me.mQueue.next(); // might block if (msg == null) {//所有消息读取完毕才会停止 // No message indicates that the message queue is quitting. return false; } // 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); } //...省略非重点解读代码 if (observer != null) { token = observer.messageDispatchStarting(); } long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid); try { msg.target.dispatchMessage(msg);//读取出来的消息通过Handler回调出去 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); } } //....省略 msg.recycleUnchecked(); return true; }
}
Looper通过MessageQueue里的具体Message持有的 target调用dispatchMessage()方法
我们来看一下 msg.target.dispatchMessage
public final class Message implements Parcelable { @UnsupportedAppUsage /*package*/ Handler target; }
public class Handler {
public void dispatchMessage(@NonNull Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg);//这就是大家熟悉的消息接收方法 } } }
所以其实Hanlder的 handleMessage()就是简单的回调而已,并没有什么神秘的。
从上面看来Looper就是一个简单的MessageQueque循环遍历而已,好像跟跨线程没有太大的关系,消息回调到哪个线程还是取决于哪个线程调用了loop()方法
不着急我们继续看以下两个方法的源码
runOnUiThread(new Runnable() { @Override public void run() { } });
或者 handler.post(new Runnable(){
});
public final void runOnUiThread(Runnable action) { if (Thread.currentThread() != mUiThread) { mHandler.post(action);//最终调用的还是mHandler.post(action),只不过这个mHandler是Activity持有的Handler } else { action.run(); } }
public final boolean post(@NonNull Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
public boolean sendMessageAtTime(@NonNull 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(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) { msg.target = this; msg.workSourceUid = ThreadLocalWorkSource.getUid(); if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis);//消息加入了队列 }
所以mHandler.post()就是把消息加入了队列,等待被遍历,好像和跨线程还是没什么关系。我们来看一下如下源码大概就明白了
public Handler(@Nullable 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();//handler创建的时候就去获取了Looper,并存储了起来 if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
public class ThreadLocal<T> {
public T get() {//Thread里面的 ThreadLocalMap 存储了Looper,所以Thread和Looper是一对一绑定的 Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
}
总结:所以Handler创建的时候,会去获取myLooper,而myLooper是和线程一对一绑定的,一个线程对应只有一个Looper。所以Handler 一旦执行new,就持有了创建时候所在线程的Looper,那么消息自然就回调给Handler创建时的线程。消息的回调机制是严重依赖Handler在哪个线程创建的。
至于loop()方法在哪里被调用了,主线程在ActivityThread的main方法,如下
public final class ActivityThread extends ClientTransactionHandler implements ActivityThreadInternal {
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>"); 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); Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
子线程的Loop()在什么时候调用呢?我们先说结论,子线程没有调用loop(),需要开发者自己调用loop()。
由于涉及到线程的创建,篇幅较长,我们祥见下一章