我们都知道平时在子线程要刷新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()。
由于涉及到线程的创建,篇幅较长,我们祥见下一章
深入理解Android中的Handler、Looper与MessageQueue机制

3321

被折叠的 条评论
为什么被折叠?



