Handler、Looper、Message 和 Thread 的合作机制——安卓 Handler 机制、跨线程机制详解

        我们都知道平时在子线程要刷新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()。

    由于涉及到线程的创建,篇幅较长,我们祥见下一章

 Java Thread 的创建_闽农的博客-CSDN博客

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闽农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值