博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android消息机制Handler源码分析
阅读量:6277 次
发布时间:2019-06-22

本文共 12949 字,大约阅读时间需要 43 分钟。

一. 常用的几种方式

// 方式1Handler handler = new Handler();Message message = Message.obtain();handler.sendMessage(message);// 方式2Handler handler = new Handler(Looper.getMainLooper());handler.post(new Runnable(){...});复制代码

二. MessageQueue原理

/**     * Handler.sendMessage -> Handler.sendMessageDelayed     */    public final boolean sendMessageDelayed(Message msg, long delayMillis)    {        if (delayMillis < 0) {            delayMillis = 0;        }        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);    }    // sendMessage最终会调用sendMessageAtTime这个方法    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {        MessageQueue queue = mQueue;        if (queue == null) {            RuntimeException e = new RuntimeException(                    this + " sendMessageAtTime() called with no mQueue");            Log.w("Looper", e.getMessage(), e);            return false;        }        return enqueueMessage(queue, msg, uptimeMillis);    }    // 将我们创建的这个Message投放到消息队列中去    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);    }复制代码

好了上面我们看到, 我们创建的Message最后会被投放到消息队列中去, 这个消息队列做了哪些处理呢, 我们跟进入MessageQueue中去看看

boolean enqueueMessage(Message msg, long when) {        if (msg.target == null) {            throw new IllegalArgumentException("Message must have a target.");        }        // 若这个Message已经标记为正在被使用, 则抛出异常        if (msg.isInUse()) {            throw new IllegalStateException(msg + " This message is already in use.");        }        synchronized (this) {            if (mQuitting) {                IllegalStateException e = new IllegalStateException(                        msg.target + " sending message to a Handler on a dead thread");                Log.w(TAG, e.getMessage(), e);                msg.recycle();                return false;            }            msg.markInUse();// 将当前我们传入的Msg标记为正在使用的状态            msg.when = when;// 该msg发送的时间            Message p = mMessages;// mMessages为MessageQueue的首元素            boolean needWake;             // 1. 这个if判断是为了确定在未来一段时间里会最先发送的msg, 将其插入到Message链表的首部            if (p == null || when == 0 || when < p.when) {                // New head, wake up the event queue if blocked.                msg.next = p;// 插入到链表首部                mMessages = msg;// 让mMessage指向链表的首元素                needWake = mBlocked;            } else {                needWake = mBlocked && p.target == null && msg.isAsynchronous();                Message prev;                // 2. 这个for循环从链表的首部开始, 找寻一个适合msg插入的位置, 将其插入到prev的后面和p的前面                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;            }            // We can assume mPtr != 0 because mQuitting is false.            if (needWake) {                nativeWake(mPtr);            }        }        return true;    }复制代码

我们看到从if (p == null || when == 0 || when < p.when)开始往下的代码就开始了Message的链表操作了 这里我们指定:

  • Message msg1 = Message.obtain(); handler.sendMessage(message);
  • Message msg2 = Message.obtain(); handler.sendMessageDelay(message, 1000);
  • Message msg3 = Message.obtain(); handler.sendMessageDelay(message, 500);
  1. 当我们的消息msg1进入MessageQueue时
    • msg1.when = when; (msg1.when = 0)
    • Message p = mMessages (p = null)
    • ==if (p == null || when == 0 || when < p.when) 显然满足==
    • msg1.next = p; (msg1.next = null)
    • mMessages = msg1
  2. 当我们的消息msg2进入MessageQueue时
    • msg2.when = when; (msg2.when = 1000)
    • Message p = mMessages; (Message p = msg1)
    • ==if (p == null || when(1000) == 0 || when(msg2.when -> 1000) < p.when(msg1.when -> 0)) 不满足条件==
    • Message prev = p; (Message prev = mMessages -> Message prev = msg1)
    • p = p.next; (p = mMessages.next -> p = msg1.next -> p = null )
    • ==if (p == null || when(msg2.when -> 1000) < p.when(null) ) 显然满足条件, break, 退出死循环==
    • msg2.next = p; (msg2.next = null)
    • prev.next = msg2;(mMessages.next = msg2 -> msg1.next = msg2)// 这样就建立了msg1与msg2的链表关系
  3. 当我们的消息msg3进入MessageQueue时
    • msg3.when = when; (msg3.when = 500)
    • Message p = mMessages; (Message p = msg1)
    • ==if (p(msg1) == null || when(500) == 0 || when(msg3.when -> 500) < p.when(msg1.when -> 0)) 不满足条件==
    • Message prev = p; (Message prev = mMessages -> Message prev = msg1)
    • p = p.next; (p = mMessages.next -> p = msg1.next -> p = msg2 )
    • ==if (p(msg2) == null || when(msg3.when -> 500) < p.when(msg2.when -> 1000) ) 显然满足条件, break, 退出死循环==
    • msg3.next = p; (msg3.next = msg2)
    • prev.next = msg3;(msg1.next = msg3) 真是令人惊叹, 我们发送的Message经过这套算法之后, 按照时间发送早晚的顺序链接排序好了

可以看到主要的算法就是使用了一个重要的if判断和一个for循环:

  • if (p == null || when == 0 || when < p.when)
    • 这个if判断是为了确定在未来一段时间里会最先发送的msg
    • 将其插入到Message链表的首部
    • 让mMessages指向链表的首部
  • for (;;)这个for循环从链表的首部开始, 找寻一个适合当前传入的msg插入的位置, 将其插入到prev的后面和p的前面

Summary:

sendMessage方法只是将我们创建的Message投放到消息队列MessageQueue, 这个队列是以链表的方式按照msg发送时间的顺序排列

三. Looper消息循环机制

在线程中无法直接创建Handler

public Handler(Callback callback, boolean async) {        if (FIND_POTENTIAL_LEAKS) {            final Class
klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } // 从Handler的构造方法可知, Handler是无法再直接在子线程中创建的 mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } // 这里有个Queue, Nice, This is MessageQueue mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }复制代码

正确创建Handler的姿势如下

// 在子线程中创建    Thread({        // 1. 准备Looper循环        Looper.prepare()        Handler()        Log.e("TAG", Thread.currentThread().toString())        // 2. 开启循环        Looper.loop()    }).start()        // Android的主线程中ActivityThread.class    public static void main(String[] args) {        ...        // 可以看到这里也执行了Looper的prepare方法        // 我们能在主线程中直接创建Handler肯定也不是凭空来的        Looper.prepareMainLooper();        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }        if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }        Looper.loop();    }复制代码
  1. 分析Looper的prepare方法
public static void prepare() {        prepare(true);    }    public static void prepareMainLooper() {        prepare(false);        synchronized (Looper.class) {            if (sMainLooper != null) {                throw new IllegalStateException("The main Looper has already been prepared.");            }            sMainLooper = myLooper();        }    }        private static void prepare(boolean quitAllowed) {        if (sThreadLocal.get() != null) {            throw new RuntimeException("Only one Looper may be created per thread");        }        // 将我们的Looper set进ThreadLocalMap中        // static final ThreadLocal
sThreadLocal = new ThreadLocal
(); sThreadLocal.set(new Looper(quitAllowed)); } // 可以看到获取当前线程的Looper是通过sThreadLocal.get()拿到的 public static @Nullable Looper myLooper() { return sThreadLocal.get(); } 复制代码

1.1 刚分析了prepare的源码就发现一个非常重要的ThreadLocal sThreadLocal: static final ThreadLocal sThreadLocal = new ThreadLocal(); 我们跟进去搞清楚

// ThreadLocal.class 的set方法    public void set(T value) {        // 一个线程中有一个唯一的ThreadLocalMap用于存储键值对        Thread t = Thread.currentThread();        ThreadLocalMap map = getMap(t);//  ThreadLocalMap map = t.threadLocals;        if (map != null)            // key: ThreadLocal, value: T            map.set(this, value);        else            // 给线程创建 ThreadLocalMap 并且将当前的 TheadLocal 和 value 加入其中            // 一般情况下在线程初始化时会被自动创建            createMap(t, value);// t.threadLocals = new ThreadLocalMap(this(当前ThreadLocal的实例), value);    }    public T get() {        Thread t = Thread.currentThread();        ThreadLocalMap map = getMap(t);        if (map != null) {            ThreadLocalMap.Entry e = map.getEntry(this);            if (e != null) {                @SuppressWarnings("unchecked")                T result = (T)e.value;                return result;            }        }        // 通过跟进源码可知initialValue就是null        return setInitialValue();    }复制代码

可以看到, 我们的sTheadLocal.set(value)方法, 将sThreadLocal和value值set进了ThreadLocalMap中, 这个ThreadLocalMap在一个线程中是唯一的, 而sThreadLocal的value又对应了我们new 的Looper对象, 这样我们就可以通过sTheadLocal.get()方法去获取到我们存入的value了, 这里主要分析Looper相关机制, 对于ThreadLocal存储的细节这里不做深究

  1. 接下来看看Looper.loop做了哪些操作
/**     * Run the message queue in this thread. Be sure to call     * {@link #quit()} to end the loop.     */    public static void loop() {        final Looper me = myLooper();        // 在new Looper()的时候, 会创建一个MessageQueue对象        // 这里获取到这个MessageQueue对象        final MessageQueue queue = me.mQueue;        for (;;) {// 可以看到这里是个死循环            // 从MessageQueue队列中取出下一个需要执行Message            Message msg = queue.next(); // might block            if (msg == null) {                // No message indicates that the message queue is quitting.                return;            }            try {                msg.target.dispatchMessage(msg);            } finally {                if (traceTag != 0) {                    Trace.traceEnd(traceTag);                }            }            msg.recycleUnchecked();        }    }复制代码

上述代码中有两行非常值得关注

  • Message msg = queue.next();// 从消息队列中取出当前时间节点需要执行的msg
  • msg.target.dispatchMessage(msg);// 分发这个取出的msg

2.2 看看MessageQueue.next()方法是如何取出msg的

// 从MessageQueue中取出一下个需要执行的Message    Message next() {        ...         // 可以看到MessageQueue的next方法也是一个死循环        for (;;) {            ...            synchronized (this) {                // 尝试从Queue中取出下一个需要执行的Message                final long now = SystemClock.uptimeMillis();                Message prevMsg = null;                Message msg = mMessages;                // 判断当前Queue首部的Msg是否绑定了Target(Handler), 即判断mMessge是否可用                if (msg != null && msg.target == null) {                    // 循环找出当前队里第一个可用的msg                    do {                        prevMsg = msg;                        msg = msg.next;                    } while (msg != null && !msg.isAsynchronous());                }                if (msg != null) {                    // 判断当前时间节点是否大于Msg需要执行的时间                    if (now > msg.when) {                        if (prevMsg != null) {                            // msg即将被取出, 所以它之前的prevMsg的next直接链接上msg的next                            prevMsg.next = msg.next;                        } else {                            // msg即将被取出, 队首元素指向下一个                            mMessages = msg.next;                        }                        // 将这个msg指向的下一个位置置空                        msg.next = null;                        // 标记为使用状态                        msg.markInUse();                        // 将msg取出, 返回出去                        return msg;                    }                } else {                    // No more messages.                }                // Process the quit message now that all pending messages have been handled.                if (mQuitting) {                    dispose();                    return null;                }            }        }    }复制代码

从上面的代码中可以看到Looper.loop中维护了一个for(;;)死循环, MessageQueue.next中也维护了一个for(;;)死循环

  • 第一个死循环的作用是: 循环的从MessageQueue中取出msg, 通过dispatchMessage分发并处理
  • 第二个死循环的作用是: 循环的从MessageQueue中尝试去取出当前可以执行的msg, 将其返回给Loop的loop方法处理并分发

2.3 Handler的dispatchMessage分发处理Msg

/**     * Handle system messages here.     * 终于我们最终还是走到了这个方法中去处理Msg     */    public void dispatchMessage(Message msg) {        // priority1: 处理msg携带的callback        if (msg.callback != null) {            handleCallback(msg);        } else {            // priority2: 处理给Handler设置的mCallback对象中的handleMessage方法            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            // priority3: 处理Handler重写的handleMessage(msg)方法            handleMessage(msg);        }    }复制代码

分析到这里整个安卓的消息机制就明了了, 接下来总结一波

总结

  1. 创建Handler首先要初始化当前线程的Looper, 即Looper.prepare()
  2. 在Looper创建的时, 会创建当前线程的MessageQueue消息队列即Looper.mQueue
  3. 当我们通过Handler在其它线程中发送Message时, 会将其投递到Handler创建线程所在的MessageQueue中
  4. 在Handler创建线程的Looper.loop()方法中, 会不断的循环通过MessageQueue.next()取出当前时间节点需要执行的Message
  5. 取出Message后通过 msg.target.dispatchMessage(msg) 方法分发处理这个Msg, 至此就走到了handleMessage()中

转载地址:http://stgpa.baihongyu.com/

你可能感兴趣的文章
计算机网络与Internet应用
查看>>
Django 文件下载功能
查看>>
走红日本 阿里云如何能够赢得海外荣耀
查看>>
磁盘空间满引起的mysql启动失败:ERROR! MySQL server PID file could not be found!
查看>>
点播转码相关常见问题及排查方式
查看>>
[arm驱动]linux设备地址映射到用户空间
查看>>
弗洛伊德算法
查看>>
【算法之美】求解两个有序数组的中位数 — leetcode 4. Median of Two Sorted Arrays
查看>>
精度 Precision
查看>>
Android——4.2 - 3G移植之路之 APN (五)
查看>>
Linux_DHCP服务搭建
查看>>
[SilverLight]DataGrid实现批量输入(like Excel)(补充)
查看>>
秋式广告杀手:广告拦截原理与杀手组织
查看>>
翻译 | 摆脱浏览器限制的JavaScript
查看>>
闲扯下午引爆乌云社区“盗窃”乌云币事件
查看>>
02@在类的头文件中尽量少引入其他头文件
查看>>
JAVA IO BIO NIO AIO
查看>>
input checkbox 复选框大小修改
查看>>
网吧维护工具
查看>>
BOOT.INI文件参数
查看>>