Android Handler机制核心浅析

1.简要概述

Handler负责发送Message到MessageQueue,Looper负责从MessageQueue取消息,最后消费者在Handler.handleMessage(Message msg)函数消费。

一个线程只能有一个Looper和一个MessageQueue(利用了ThreadLocal),一个Looper可以绑定多个Handler,Handler可以发送多个Message。

Handler发消息会把this指针写入message.target,最终messageQueue间接持有handler,此处解释Handler内部类泄漏问题(当handler持有context)。

2.屏障消息

Handler提供了静态方法构造一个异步消息 public static Handler createAsync(@NonNull Looper looper),看MessageQueue中next()中如何处理

                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                    //屏障消息开启后,此处只会取异步消息
                }

可是屏障还没有开启,以上代码并不会执行,如何开启屏障:postSyncBarrier(),结束屏障:removeSyncBarrier(int token),需要配对使用否则同步消息无法执行,会一直在MessageQueue中。屏障消息妙用可以让该Handler发送的消息优先级最高,适合处理一些特殊的消息。

3.Looper一直在执行for死循环,为何不会造成线程卡死?从原理处进行分析,先上Looper.looper简化源码,其中调用了MessageQueue.next()简化代码

public static void loop() {
        final Looper me = myLooper();
        //此处解释在子线程创建的Looper一定要调用Looper.prepare,否则直接报异常
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;
        for (;;) {
            //从MessageQueue中取消息
            Message msg = queue.next(); // might block
            //没有消息则退出死循环
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

        }
    }
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;//返回nullLooper退出循环
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);
            //此处会调用native方法nativePollOnce是否让该线程阻塞
        }
}

从上面分析,可以得出结论:Looper退出循环或阻塞后,为何后面发消息后依然可以处理,那还要看MessageQueue.enqueueMessage(Message msg, long when)中调用nativeWake(mPtr),此方法此处会唤醒线程同时调用静态方法Looper.loop()。通俗讲当该线程阻塞后会释放cpu资源,不会造成卡死,当有消息后线程被唤醒,继续执行消息(此处对native方法不做详细分析)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值