美文网首页
Handler总结

Handler总结

作者: 拿拿guardian | 来源:发表于2020-03-14 11:50 被阅读0次

    Handler如何做到切换线程

    1.Handler类里包含mLooper和mQueue;
    2.Looper类包含mQueue;
    3.目标线程通过调用Looper.prepare方法创建一个Looper对象,存在ThreadLocal里;
    4.创建Looper对象的时候,会创建一个MessageQueue队列,就是mQueue;
    5.调用Handler.post方法本质是往目标线程的mLooper的mQueue塞一条Message;
    6.Looper通过loop方法不断轮询mQueue队列,处理Message,从而实现线程切换。

    倒过来推演,如何切换线程:
    1.想办法向目标线程的mQueue塞一个Message,这一步需要Handler来实现。
    2.如何获取到目标线程的mQueue呢?mQueue在目标线程的mLooper对象里。
    3.如何获取目标线程的mLooper对象呢?两种方法:传进去一个目标线程的mLooper;通过ThreadLocal,mLooper = Looper.myLooper()获取,这一步必须在目标线程执行;
    5.所以构造Handler,要么传进去一个目标线程的mLooper;要么在目标线程执行没有Looper参数的构造方法。

    关于同步屏障机制

    1.同步屏障可以通过MessageQueue.postSyncBarrier函数来设置;
    2.同步屏障就是一个Message,一个target字段为空的Message;
    3.MessageQueue的next()方法,在遇到同步屏障Message时,会返回下一个异步消息(自动忽略同步消息),变相的提高的异步消息的处理优先级。
    4.ViewRootImpl.scheduleTraversals应用到了同步屏障机制。

    Message的tagert何时赋值

    执行enqueueMessage的时候

        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);
        }
    

    底层wake机制

    1.Android 6.0版本以前,采用pipe/epoll机制。Looper初始化时会创建一个pipe,生产两个fd(读端和写端)。
    上层MessageQueue在读取消息时,走到nativePollOnce方法,线程可能会休眠:

    Message next() {
            ...
            for (;;) {
                if (nextPollTimeoutMillis != 0) {
                    Binder.flushPendingCommands();
                }
    
                nativePollOnce(ptr, nextPollTimeoutMillis); //这一步会休眠,但是有个超时时间nextPollTimeoutMillis,即下一个msg的需要被处理的时间
                ...
            }
    }
    

    而在消息入队时,会去检测是否有必要唤醒休眠的线程:

    boolean enqueueMessage(Message msg, long when) {
            ...
            if (needWake) {
                nativeWake(mPtr); //用往管道写值去唤醒休眠的线程
            }
            ...
    }
    

    2.Android 6.0 及之后版本,采用eventfd机制。相比于管道,只需要产生一个fd。

    Handler是跨线程通信,为什么用到管道这种跨进程通信机制?

    以下是个人理解:管道主要工作是用于通知另一个线程的。Handler机制一个特点就是在消息队列没有消息时线程休眠,当消息队列不为空唤醒休眠线程,是典型的生产者/消费者问题。Linux中有很多方案可以处理这类问题,pipe机制相对而言比较轻量级,所以被采用。

    相关文章

      网友评论

          本文标题:Handler总结

          本文链接:https://www.haomeiwen.com/subject/llzmshtx.html