Handler / MessageQueue / Looper 的个人理解( 源码分析 )

根据源码注释说明, handler设计目的如下:

There are two main uses for a Handler: (1) to schedule messages and
runnables to be executed as some point in the future; and (2) to enqueue
an action to be performed on a different thread than your own.

Handler有两个主要用途: 
1. 把 Message 和 Runnable 安排在未来的某个时间点执行;
2. 把某些操作放入其他的线程中执行.

注意, Handler 只是发送消息的一个工具, 并不是使用 Thread 所必须的.


具体机制

  1. Handler 初始化: 初始时会获取当前 ThreadLooper, 其中 android 主线程会自动初始化一个 Looper, 而自己创建的线程则需要自己维护 Looper(通过 Looper.prepare 创建, 通过 Looper.loop 开启处理 message 的循环 ).

        public Handler(Callback callback, boolean async) {
            mLooper = Looper.myLooper();
            if (mLooper == null) {
                throw new RuntimeException(
                    "Can't create handler inside thread that has not called Looper.prepare()");
            }
            mQueue = mLooper.mQueue; // 获取对应线程的Looper的MessageQueue
            mCallback = callback;
            mAsynchronous = async;
        }
        
    
  2. Handler发送消息: Handler 发送消息是把 Message 发送给 Looper 内的 MessageQueue, 所有类型的消息发送到最后都是调用的 enqueueMessage. 而 handler.enqueueMessage 则是调用的 MessageQueue.enqueueMessage

    	// Handler.enqueueMessage
        private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            msg.target = this;
            if (mAsynchronous) {
                msg.setAsynchronous(true);
            }
            return queue.enqueueMessage(msg, uptimeMillis);
        }
    
    // MessageQueue.enqueueMessage 省略了部分代码
    boolean enqueueMessage(Message msg, long when) {
        synchronized (this) {
            if (mQuitting) {
                msg.recycle();
                return false;
            }
    
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // 如果当前队列为空/已阻塞, 则唤醒
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // 没有阻塞, 把新消息放入消息队列中(链表)
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }
    
  3. 处理消息: Looper 中会死循环查找 MessageQueue, 如果next Message != null, 那么这个 message 就会交给它内部的 target Handler 处理 (msg.target.dispatchMessage(msg)) ;

    // 省略了部分代码, 仅保留逻辑部分
    public static void loop() {
        final Looper me = myLooper();
        final MessageQueue queue = me.mQueue;
        for (;;) {
            Message msg = queue.next(); // 可能阻塞
            if (msg == null) {
                return;
            }
            msg.target.dispatchMessage(msg);
            msg.recycleUnchecked(); // 清空
        }
    }
    
    	/**
    	* 由此可知, 如果message中包含runnable, 或者Handler实例化时传入了callback,
    	* 那么handler子类重写的handleMessage就不会执行了. 
    	*/ 
        public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
    	        // 调用 Message 内部的 Runnable callback
                handleCallback(msg); 
            } else {
                if (mCallback != null) {
    	            // 使用构造方法中传入的Handler内部的Callback接口
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                // 或者使用子类的处理方式
                handleMessage(msg);
            }
        }
    

新建Thread的两种方式

第一种:

        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.i("TAG", "run on Runnable");
            }
        }) {
            @Override
            public void run() {
                super.run();
                Log.i("TAG", "run on Thread");
            }
        }.start();

这种创建方式线程在执行完代码后( 先执行 Thread.run, Runnable 的 run 执行在 Thread.run 的 super 里面 )就结束了.

第二种:

        new Thread(new Runnable() {
            @Override
            public void run() {
	            Looper.prepare();
                Log.i("TAG", "run on Runnable");
                Looper.loop();
            }
        }).start();

这种方式开启了死循环, Thread 会一直存活下去. 可以命名此 Thread, 使用 getLooper().quit 来销毁.


HandlerThread

这个类继承自Thread,并在内部start时自动创建出Looper循环,所以可以使用new Handler(HandlerThread.getLooper())的方式很方便的去关联一个Handler,在循环开启一个较长时间存活的子线程时可以使用。如果不再需要时,可以通过HandlerThread.quitSafely去退出该线程。


Handler的bug

在使用Handler去循环发送消息时容易出现丢失消息的问题,例如多次在接收到消息时再次延迟发送一个消息时最容易出现,这种场景下就不要使用Handler的方式去处理了,可以直接在Thread.run中添加sleep处理。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值