Android 消息机制之消息的其他处理深入源码分析 [ 九 ]

Android 消息机制深入源码分析 [ 一 ]
Android 消息机制之 ThreadLocal 深入源码分析 [ 二 ]
Android 消息机制之 Looper 深入源码分析 [ 三 ]
Android 消息机制之 Message 与消息对象池的深入源码分析 [ 四 ]
Android 消息机制之 MessageQueue 深入源码分析 [ 五 ]
Android 消息机制之初识Handler [ 六 ]
Android 消息机制之 Handler 发送消息的深入源码分析 [ 七 ]
Android 消息机制之 MessageQueue.next() 消息取出的深入源码分析 [ 八 ]
Android 消息机制之消息的其他处理深入源码分析 [ 九 ]
Android 消息机制总结 [ 十 ]

上一章分析学习了消息机制中重要的取出操作, 本章对剩余消息分发处理, 移除, 查看消息是否存在等的分析.
先来看消息的分发处理.

1. Handler.dispatchMessage(Message msg)

Looper.loop() 方法内调用. 先从 MessageQueue 中获取到一个消息后, 再调用这个方法传入获取的消息进行分发处理.
Handler.java 97 行.

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        //当 Message 存在回调方法, 回调 msg.callback.run() 方法
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            //当创建 Handler 时, 传入的参数为 Callback 的时候, , 回调方法为 Handler.Callback.handleMessage()
            //在第六篇中有分析到这个 Callback.
            //如果我们实现的 Callback 接口中 handleMessage 返回 true, 则表示不会调用 Handler 自身的 HandleMessage() 方法.
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        //Handler 自身的回调方法 handlerMessage()
        handleMessage(msg);
    }
}

在分发消息三个方法啊的优先级

  • Message 的回调方法优先级最高. 既 message.callback.run()
  • Handler 的回调方法次之, 既 Handler.Callback.handleMessage
  • Handler 的默认方法优先级最低.

很多情况下, 消息分发后的处理都是第三种情况, 一般往往都是通过复写第三种方法, 从而实现自己的业务逻辑.

 

2. 消息的移除

消息的移除其实就是根据身份 what / Runnable / msg.obj 移除队列中对应的消息, 例如发送消息时, 用同一个 msg.what 作为参数, 所有方法最终调用 MessageQueue.removeMessages 来操作.

调用方法的入口依然是在 Handler.java 中

public final void removeCallbacks(Runnable r) {
  mQueue.removeMessages(this, r, null);
}

public final void removeCallbacks(Runnable r, Object token) {
  mQueue.removeMessages(this, r, token);
}

public final void removeMessages(int what) {
  mQueue.removeMessages(this, what, null);
}

public final void removeMessages(int what, Object object) {
  mQueue.removeMessages(this, what, object);
}

public final void removeCallbacksAndMessages(Object token) {
  mQueue.removeCallbacksAndMessages(this, token);
}

不难看出 Handler 中的删除工作, 其实都是通过调用 MessageQueue 来操作的.
MessageQueue 中的消息移除又有以下几个方法

void removeMessages(Handler , int , Object )
void removeMessages(Handler, Runnable,Object)
void removeCallbacksAndMessages(Handler, Object)
void removeAllMessagesLocked()
void removeAllFutureMessagesLocked()

先来看第一个.

MessageQueue.removeMessages(Handler , int , Object )
MessageQueue.java 641 行

void removeMessages(Handler h, int what, Object object) {
    //分析 1
    if (h == null) {
        return;
    }
    synchronized (this) {
        //分析 2
        Message p = mMessages;

        //分析 3
        while (p != null && p.target == h && p.what == what&& (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }
        //分析 4
        while (p != null) {
            Message n = p.next;
            if (n != null) {
                if (n.target == h && n.what == what && (object == null || n.obj == object)) {
                    Message nn = n.next;
                    n.recycleUnchecked();
                    p.next = nn;
                    continue;
                }
            }
            p = n;
        }
    }
}
  • 分析
  1. 对传进来的 Handler 做非空判断, 如果传进来的 Handler 为空, 则直接返回.
  2. 获取消息链表的头元素
  3. 如果从消息链表获取的头部元素符合删除条件的 Message, 就从头开始遍历删除所有符合条件的 Message,并放入消息池.
  4. 如果消息链表的头部元素不符合分析 3, 或者在执行完分析 3 后,当前的 Message 不符合条件. 就会到分析 4 中, 判断当前 Message 的下一个消息是否符合条件.

 
从消息队列中移除 Message 的操作就是遍历消息队列然后移除所有符合条件的 Message. 但是这里有个细节. 从代码中可以看出移除是分了两步操作. 第一次先判断符合删除条件的 Message 是不是从消息队列的头部就开始有了, 这时候会修改 mMessage 指向的问题, 而 mMessage 代表的就是整个消息链表, 排除了第一种情况之后, 剩下的就是继续遍历队列移除剩余符合条件的 Message, 其他重载方法也基本类似这样的流程, 不同的就是条件不同而已. 下面直接分析 removeAllFutureMessagesLocked() 这个方法.
 
MessageQueue.removeAllFutureMessagesLocked()
MessageQueue.java 752 行.

private void removeAllFutureMessagesLocked() {
    //分析 1
    final long now = SystemClock.uptimeMillis();
    //分析 2
    Message p = mMessages;
    if (p != null) {
        //分析 3
        if (p.when > now) {
            removeAllMessagesLocked();
        } else {
            //分析 4
            Message n;
            for (;;) {
                n = p.next;
                if (n == null) {
                    return;
                }
                if (n.when > now) {
                    break;
                }
                p = n;
            }
            //分析 5
            p.next = null;
            do {
                p = n;
                n = p.next;
                p.recycleUnchecked();
            } while (n != null);
        }
    }
}

删除所有未来的消息.

  • 分析
  1. 获得当前时间(从手机开机到现在的时间)
  2. 获取消息队列中消息链表的头元素赋值给 p
  3. 如果 p 的执行时间大于当前时间, 就删除链表中的所有数据. (因为链表中的排序是有序的, 如果第一个执行时间都大于当前时间了, 意味着整个链表所有元素的执行时间都大于当前时间)
  4. 如果消息队列中 p 的执行时间小于当前时间, 则说明需要遍历消息队列通过对比时间找到合适的消息进行移除.
  5. 找到合适的消息后, 就开始移除这个消息到消息队列尾部的所有元素.

 

3. 查看消息是否存在

入口同样也是在 Handler 中. 有 3 个入口

// Handler.java
public final boolean hasMessages(int what) {
    return mQueue.hasMessages(this, what, null);
}

public final boolean hasMessages(int what, Object object) {
    return mQueue.hasMessages(this, what, object);
}

public final boolean hasCallbacks(Runnable r) {
    return mQueue.hasMessages(this, r, null);
}

内部同样调用的也是 MessageQueue.hasMessages 方法.

MessageQueue.hasMessages(Handler h, int what, Object object)
MessageQueue.java 590 行

boolean hasMessages(Handler h, int what, Object object) {
    //分析 1
    if (h == null) {
        return false;
    }
    synchronized (this) {
        //分析 2
        Message p = mMessages;
        //分析 3
        while (p != null) {
            if (p.target == h && p.what == what && (object == null || p.obj == object)) {
                return true;
            }
            p = p.next;
        }
        return false;
    }
}
  • 分析
  1. 判断传入进来的 Handler 是否为 null, 如果 null 就直接返回 false. 表示没有找到.
  2. 获得消息队列中的头部元素
  3. 遍历消息队列链表中所有的消息, 如有有消息符合指定条件, 则返回 true. 若遍历结束也没有, 就返回 false

剩下的也都基本是这个流程, 就不再分析. 不同的只是筛选条件不同.

到这里, Android 消息机制的 消息入队, 消息取出, 消息处理, 消息移除, 已经全部分析学习完了, 下一章将学习一个新的内容 HandlerThread.

你可能感兴趣的:(Android 消息机制之消息的其他处理深入源码分析 [ 九 ])