Android开发经验谈Android开发

Handler简单回顾流程

2019-08-23  本文已影响0人  space0o0

初学android,我们总是被告诫,不能在子线程中更新界面,请用handler。

本文就带大家浅显的理解handler更新界面原理,尽量避免过多源码分析,只贴关键代码帮助记忆。

目录:

handler中存在的重要角色

Handler

handle 字面意思:操作,搬运;在程序中理解成搬运工,操作员。
搬运什么呢?搬运消息;什么消息?更新界面的消息。
就这么简单。

MessageQueue

messageQueue中文翻译过来叫:消息队列;
那么handler搬运的消息去哪里了?就放在这个队列中,可以想象成一堆消息排队中,handler搬来的消息都放在了这里,等待被消耗。

Looper

loop中文叫循环;
循环干什么?不停的从消息队列中获取消息。

handler更新流程

/**
 * 1.在UI线程新建handler
 */
fun initHandler() {
    mainHandler = @SuppressLint("HandlerLeak")
    object : Handler() {
        override fun handleMessage(msg: Message?) {
            super.handleMessage(msg)
            //接收不同的消息,做不同的处理
        }
    }
}
/**
 * 2.发送消息
 */
fun sendMessage(){
    mainHandler.sendMessage(Message())
}

handler有各式各样的send方法,最终都调用sendMessageAtTime方法

//msg:handler搬运的消息
//uptiomeMillis:延时发送 单位 ms
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);//放入消息队列
}

此方法的最终目的就是把消息放到队列中

boolean enqueueMessage(Message msg, long when) {
...其他无关代码...
        msg.markInUse();
        msg.when = when;//消息的发送时间
        Message p = mMessages;
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            //如果消息队列是空的;
              //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) {
                    //在消息队列根据when的先后顺序,寻找新消息插入的位置
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
              //把消息插入队列中
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

通过对消息队列的添加策略,我们得知,消息队列是按照消息执行的先后时间排序的。when越小,排在越前面;
读懂源码的知识点:数据结构中队列的结构和操作。

Looper.loop();//开启Looper,该干活了

Message msg = queue.next();//获取新的消息

//MessageQueue的next()方法
for (;;) {
    if (nextPollTimeoutMillis != 0) {
        Binder.flushPendingCommands();
    }
    //从队列中拉取消息,nextPollTimeoutMillis=0表示立即拉取
    nativePollOnce(ptr, nextPollTimeoutMillis);

    synchronized (this) {
        final long now = SystemClock.uptimeMillis();
        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) {
                // now:当前时间     msg.when:消息的通知时间
                // 消息的通知时间还不到,计算下次拉取message的时间
                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;
                if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                msg.markInUse();
                //返回执行的消息
                return msg;
            }
        } else {
            nextPollTimeoutMillis = -1;
        }

        if (mQuitting) {
            dispose();
            return null;
        }
}

最后调用dispatchMessage通知handler做相应的界面更新

总结一下就是:handler发送消息,MessageQueue保存消息,Looper循环取出消息通知更新界面。

其他handler的细节和知识点在下节分析~

上一篇 下一篇

猜你喜欢

热点阅读