Handler 源码学习与分析

目录

Handler.png

Message

Message中一些常见的参数与API

public final class Message implements Parcelable{
    public int what; // 消息的id
    public int arg1; // 整数参数1
    public int arg2; // 整数参数2
    public Object obj; // 任意类型参数
    int flags; // 消息标记:正在使用异步还是同步
    Bundle data; //消息附带的额外数据
    long when; // 消息被处理的时间
    Handler target; // 消息的接收与处理者
    Messge next; // 下一个消息的指针
    private static final Object sPoolSync = new Object(); // 消息池使用的对象锁
    private static Message sPool; // 消息池
    private static int sPoolSize = 0;

    private static final int MAX_POOL_SIZE = 50; // 消息池的最大容量,为什么设置为50
    public static Messgae obtain(){} // 复用消息池中的消息
    void recycleUnchecked(){} // 回收并清理消息(msg.target = null;sPool = this)
    public void sendToTarget(){target.sendMessage(this);} // 发送给消息绑定的Handler
    
    // 复用对象池中的消息对象
    public static Message obtain() {
        synchronized (sPoolSync) { // 加锁同步
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next; // 将指针移动到下一个节点
                m.next = null; // 从链表中断开连接
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
    // 回收消息对象
    void recycleUnchecked() {
        ... 重置消息对象中的属性 ...
        
        target = null; // 主动断开与 handler 的引用关系
        
        // 形成消息池链表。注意:第一个插入的节点作为尾节点
        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
}

小结:

1. 由于Message定义了下一个消息的指针,因此它组成了一个消息链表(重增删,轻查询);
2. 在Looper.loop()从消息队列中读取一个消息后,首先调用**msg.target.dispatchMessage(msg)** 将消息回传给 **handleMessage()**,最后调用**msg.recycleUncheckd()** 对消息进行重置回收。
3. 使用handler.obtainMessage()复用消息时,其实是从对象池链表中移除一个message对象再返回给调用者。
4. 在使用recycleUncheckd进行回收时,会主动断开与 handler 的引用关系。所以,handler并不会一定造成内存泄露
MessageQueue

MessageQueue中一些常见的参数与API

public final class MessageQueue{
    public boolean mQuitAllowed;
    Message mMessages; // 当前要处理的消息
    private boolean mBlocked; // 表明线程是否阻塞在pollOnce上
    private boolean mQuitting; // 是否主动退出循环
     
    private void native nativePollOnce() // 阻塞线程
    private void native static nativeWake(); // 唤醒被阻塞的线程
    
    boolean enqueueMessage(msg){}
    public int postSyncBarrier(){} // 发送一个同步屏障,阻塞同步消息
    
    // 添加消息至消息队列
    boolean enqueueMessage(Message msg, long when) {
        synchronized (this) {
            msg.markInUse(); // 标记为在用,不可被回收
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                Message prev;
                // 从头开始遍历链表
                for (;;) {
                    prev = p;
                    p = p.next;
                    // 到达尾节点或者消息执行时间靠前则返回
                    if (p == null || when < p.when) {
                        break;
                    }
                }
                // 插入消息队列中
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }
        }
        return true;
    }
    // 读取消息
    Message next() {
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0; // native 线程阻塞的超时时间
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
            nativePollOnce(ptr, nextPollTimeoutMillis);
            synchronized (this) {
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // 如果遇到消息屏障,则过滤掉同步消息,读取异步消息
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // 消息执行时间还没到,设置超时时间,期间阻塞在native层,不进行遍历,防止CPU占用
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // 消息已经准备好,可以处理消息了
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null; // 从队列中移出
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // 没有可处理的消息
                    nextPollTimeoutMillis = -1;
                }
                // 在没有待处理消息时,如果通知退出,则执行退出
                if (mQuitting) {
                    dispose();
                    return null;
                }
                // 处理 IdleHandler
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    mBlocked = true;
                    continue;
                }
                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler
                boolean keep = false;
                try {
                    keep = idler.queueIdle(); // 执行 IdleHandler
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }
                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }
            pendingIdleHandlerCount = 0;
            nextPollTimeoutMillis = 0;
        }
    }
    // 移除队列中的所有消息
    private void removeAllMessagesLocked() {
        Message p = mMessages;
        while (p != null) {
            Message n = p.next;
            p.recycleUnchecked(); // 回收该消息
            p = n;
        }
        mMessages = null;
    }
}

小结:

1. MessageQueue采用链表来管理消息,其mMessages是当前要处理的消息;
2. Looper.loop中调用queue.next()函数, 从消息队列中读取一个消息,若队列中没有消息,则先处理 IdleHandler, 然后阻塞在nativePollOnce()上;若链表中有消息,则会检测当前消息是不是**同步屏障** ,若是则过滤所有的同步消息,只遍历获取异步消息,然后从链表中**删除并得到**该消息。
3. 调用enqueueMessage()向消息链表中添加消息,若链表中还没有消息,则直接作为消息链表的head,并调用nativeWake()唤醒阻塞在nativePollOnce()上的线程;若消息链表中有消息,比较 *msg.when* ,按照时间顺序添加进队列,检测是否需要调用nativeWake()。
4. 消息队列维护的消息链表是按照严格按照时间顺序排列的
5. 在从队列中移出消息时,会将该消息回收,添加到Message 的消息池中
Handler

Handler中的重要参数和API

public class Handler{
    final Looper mLooper; // 循环读取消息队列中的消息的钩子
    final MessageQueue mQueue; // Looper维护的消息队列
    final Callback mCallback; // 处理消息的回调
    // 指定Looper的构造函数
    public Handler(Looper looper){
        this.mLooper = looper;
        this.mQueue = looper.mQueue;
        ***
    }
    // 不指定Looper的构造函数
    public Handler(){
        this.mLooper = Looper.myLooper(); // 通过ThreadLocal.get()获取该线程的Looper
        if(mLooper == null){
            throw RuntimeExcption("*********");
        }
        this.mQueue = mLooper.mQueue;
        ***
    }
    // 向消息队列添加消息
    pulbic final boolean postDelayed(Runnable runnable, long delayMillis){
        return sendMessageAtTime(getPostMessage(runnable), delayMillis);
    }
    public final boolean sendMessage(Message msg){
         return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);;
    }    
    private static Message getPostMessage(Runnable r, Object token) {
        Message m = Message.obtain();
        m.obj = token;
        m.callback = r; // 指定了回调处理者
        return m;
    }
    public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            return false;
        }
        // 加入消息队列
        return enqueueMessage(queue, msg, uptimeMillis);
    }
    // 移除指定消息
    public final void removeMessage(int mhat){
        mQueue.removeMessages(this, what, null);
    }
    // 移除所有的消息
    public final void removeCallbacksAndMessages(Handler handler, Object obj){
        mQueue.removeCallbacksAndMessage(this,obj);
    }
    // 复用Message
    public final Message obtainMessage(){
        return Message.obtain();
    }
    // 委派消息
    public void dispatchMessage(Message msg){
        if(msg.callback != null){ // 优先处理指定了消息处理者的消息
            handleCallback(msg);
        } else {
            if(mCallback != null){
                mCallback.handleMessage(msg);
            }else{
                handleMessage(msg);
            }
        }
    }
    // 处理消息的回调,子类必须实现
    public void handleMessage(Message msg){}
    
}

小结:

1. Handler必须在含有Looper对象的线程中创建,可以在任意线程发送消息,处理消息的线程都是其对应的Looper所在的线程;由对应线程的loopr对象执行loop()方法,循环从维护的消息队列中读取消息,接着调用 *dispatchMessage* 分发并处理消息;
2. post系列的函数为待发送的消息指定了回调处理者Runnable,因此该消息交由Runnable处理;send系列函数则全部交由handleMessage(msg)处理。
3. 若在Activity或者Fragment中使用Handler向消息队列添加了消息,则在onDestrory时,主动调用removeMessage()对消息进行清理回收,防止Activity或者Fragment内存泄露;
Looper

一个线程只能有一个Looper,新创建的Looper实例将保存在对应线程的**线程本地存储(ThreadLocal)**中。

Looper维护了一个消息队列MessageQueue,该消息队列在Looper的构造方法中创建,属于该Looper对象所有。一个Looper只能有一个MessageQueue.

一个含有Looper实例的线程:

class LooperThread extends Thread {
    Looper mLooper;
    private @Nullable Handler mHandler;
    public void run() {
        Looper.prepare();
        synchronized(this) {
            mLooper = Looper.myLooper();
        }
        Looper.loop();
    }
    // 该方法必须在调用 start() 后调用。
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(mLooper)
        }
        return mHandler;
    }
}

工作描述:

线程在运行状态,调用Looper.loop(),循环处理Looper维护的MessageQueue中的Message。消息添加到哪个消息队列和如何处理该消息,由Handler决定。指定了Looper就意味着指定了处理消息的线程;为消息指定的Handler则决定了用户如何处理该消息。

源码分析:

public final class Looper{
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); // 线程本地变量,由于是静态变量,所以可作为 GCRoots
    private static Looper sMainLooper; // 主线程的Looper实例 
    final MessageQueue mQueue; // Looper维护的消息队列 由于是常量,所以可作为 GCRoots
    final Thread mThread; // Looper所处的线程
    
    // ActivityThread中的 调用Looper(false),意味着只有进程不在才退出messageQueue 
    private Looper(boolean quitAllowed){
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
    public static void prepare(){
        // 确保一个线程只能拥有一个Looper实例
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        // 通过ThreadLocal维护一个Looper实例
        sThreadLocal.set(new Looper(true));
    }
    // 将looper升级为应用级别的实例对象。不建议在外调用
    public static void prepareMainLooper(){
        prepare();
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
    public static Looper myLooper(){
       return sThreadLocal.get(); 
    }
    
    // 循环读取维护的消息队列中的消息
    public static void loop(){
        final Looper me = myLooper();
        if(me == null){
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;
        ****
        for(;;){
            Message msg = queue.next(); // 可能会阻塞
            if(msg == null){ // 表明调用了 quit,消息队列需要退出   
                return;
            }
            ***
            // 分发并处理消息msg
            msg.target.dispatchMessage(msg);
        
            // 清理并回收该消息,将清理后的干净消息添加进消息池
            msg.recyleUncheckd();
        }
    }
}

小结:

1. 一个线程只有一个 Looper 实例,一个 Looper 实例维护一个 MessageQueue。
2. 消息在创建 Looper 实例的线程中被处理,消息可以在任意线程通过 handler 添加进消息队列。

问题:

1. 如果msg.next会阻塞主线程,那为什么程序运行时没感到卡顿那?  
    Handler的阻塞是通过底层的Looper.pollOnce(long delayMillis)实现的。pollOnce采用 *epoll* 机制(NIO机制的一种),在读取端阻塞时不会消耗CPU资源,所以不存在竞争资源的问题,因此不会感到卡顿。
2. 我们知道:handler 发送消息的线程与处理消息的线程可以不一样(多线程通信),那么是如何保证同步的那?
    答案是 Looper 使用了 ThreadLocal 持有 Looper 实例,意味着每一个线程都会有 Looper实例 的一个副本。
ThreadLocal
总结

Handler通信机制采用循环等待/唤醒机制,通过handler的post/send系列函数向Looper维护的消息队列中添加消息时,会唤醒阻塞在nativePollOnce处的线程,在Looper.loop循环中读取消息,然后使用handler分发处理该消息.

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值