Handler消息机制

先举个子线程中使用Handler的例子:

package com.haoran.myhandler;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    Looper looper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(){
            @Override
            public void run() {
                System.out.println("子线程中打印线程名:"+Thread.currentThread().getName());
                Looper.prepare();
                looper = Looper.myLooper();
                looper.loop();

            }
        }.start();
        Handler handler = new Handler(looper){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                System.out.println("主线程中打印线程名:"+Thread.currentThread().getName());
            }
        };
        Message message = Message.obtain();
        handler.sendMessage(message);
    }
}

大家看了这段代码估计会有疑惑,子线程中怎么没有new Looper()? Handler(looper)的构造做了什么操作?

那好,我们debug运行下
这里写图片描述

其实
从 FrameWork层 MainActivity.class –> Activity.class –> ActivityThread.class –> ActivityThread.class中的内部类(H.class) 和main方法。
这里写图片描述
Handler消息机制起了很大的作用,从四大组件的启动,模板模式进行生命周期方法的回调,都是消息机制在默默的进行着。从源码层看,安卓主线程在创建过程中,在ActivityManager的main入口,通过自动初始化了一个Looper和Handler以及handleMessage方法进行消息机制 再通过H.class中进行四大组件的消息机制的判断
消息类型定义:
消息类型
消息处理方法:
消息处理
我们说了半天的Handler消息机制的重要性好像和Handler消息机制原理没有半毛钱关系,最开始代码引发我们思考的问题依然无法回答。

下面我们从Handler消息机制的UML图,及相关类源码进一步进行分析,先上图:
这里写图片描述

这张架构图我们可以花时间分型一下,分析他们之间互相持有的关系。哈哈,这里我就简单概述一下,再走一下源码。。。

首先
作为一个合格的助手,Handler里有mQueue和mLooper对象;于是就有了消息队列MessageQueue和轮询器Looper,再将消息Message放在消息队列里面。Message记录着相对应的Handler,MessageQueue里持有Message对象,Looper通过持有的MessageQueue对象,对消息进行轮询读写

图解:
这里写图片描述

上图的代码大家应该看着不舒服,我把源码截取一点,一起走一遍,不过我们要带着问题走:
1. 消息怎么被发送到消息队列中的?
2. 消息怎么被Handler/Looper处理的?
3. Handler 对象是怎么创建出来的?
4. loop 这个方法什么时候执行?
5. Message 、Handler 、 Looper、 MessageQueue 、 Thread、 ThreadLocal直接的关系是什么呢?

我们知道,
handler.sendMessage(Messagemessage)handler.postRunnable(Runnable runnable);

都是可以发送消息的,其实post底层也是封装了sendMessage方法的,所以我们从handler.sendMessage(Message msg)开始吧 –>go

Mainactivity中 handler.sendMessage(message)

 Message message = Message.obtain();
 handler.sendMessage(message);

点进去 –>Handle.class的sendMessage方法

sendMessage
继续 –> sendMessageDelayed方法
sendMessageDelayed
继续 –> sendMessageAtTime方法
sendMessageAtTime

这里发现mQueue,按谷歌工程师开发习惯mQueue是Handler.class类里面的成员变量。那么,mQueue是在什么时候被赋值的呢?
我们找一找 –> 发现Handler(Callback callback, boolean async)构造
构造
Handler的其他构造里,同样赋值操作是Looper给的,那么mLooper是如何赋值的呢?

可以通过handler构造外界传递一个,通常我们用无参构造。哈哈,我们的例子里传递了一个looper哦,大家还记得吗?
上图里 mLooper = Looper.myLooper();

那么Looper里的myLooper()方法做了什么操作呢?点点点! –>
myLooper()方法

??sThreadLocal 又是什么啊?这里留个坑,一会儿填,咱们先刻舟求剑

好了,先回到 sendMessageAtTime方法发现,走了自己的enqueueMessage();方法,–>Handler.class 的enqueueMessage()
这里写图片描述

发现 –>

走到了MessageQueue.class 的enqueueMessage(Message msg, long when) 方法
排队1
排队2
排队3

这个方法有点长用伪代码解释一下吧

if (p == null || when == 0 || when < p.when) {
 // 当前发送的message需要马上被处理调,needWake唤醒状态置true
 } else {
 // 当前发送的message被排队到其他message的后面,needWake唤醒状态置false
 }
 .....
 // 是否唤醒主线程
 if (needWake) {
     nativeWake(mPtr);
 }

MessageQueue.enqueueMessage()执行,会往消息队列里添加Message。消息队列MessageQueue按照时间对所有的Message进行排序。
往消息队里里添加Message分为两种情况
1.当前发送的Message位于队列头部。需要马上处理消息。就会把当前的唤醒状态needWake唤醒状态置为true,唤醒主线程,让轮循器取消息。
2.当前发送的Message被排队排到了其他Message的后面。就不需要唤醒主线程了。就会把当前的唤醒状态needWake置为false。不唤醒主线程。

等等,哈哈,我们的Handler.class中enqueueMessage方法还没有分析完毕,细心的同学会发现 – >
msg.target = this;
这做了什么操作?
//1. Message的target标记为当前发送的Handler
//2. Looper取到message根据target把message分发给相应的Handler

至此,我们把Handler的发送,MessageQueue的给消息排队解释完毕了,接下来就是Looper中如何轮询获取消息,并交给Handler处理的

看Looper.class –> 核心Looper.loop()轮循
looper1
这里写图片描述

 while (true) {//死循环,轮循取消息
    // 取消息,如果没有消息,就阻塞
    Message msg = queue.next(); // might block //有可能会阻塞。
     ...
    //取消息。取到消息就发送给Handler
    msg.target.dispatchMessage(msg);
      ...
 }

queue.next()方法

 Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        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 {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            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();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        }
    }

msg.target.dispatchMessage(msg)也就是Handler.dispatchMessage方法

/**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
dispatchMessage: 先判断 Message 对象上的 callback 是否为空,
     如果不为空,执行 callback 上的 run 方法(联想到了handler.postRunnable方法了吗?)
     如果为空,让 handler 去处理消息,判断 handler 上的 mCallback 是否为空
    ①如果 mCallback 不为空,让 mCallback.handleMessage 方法来处理消息
    ②如果 mCallback 为空,才会调用 handler.handleMessage 方法来处理消息

哈哈,差不多了,还记得我们留的一个坑吗ThreadLocal看源码吧:)
这里写图片描述

很像一个map集合啊,就当是一个hashmap集合吧,我们android中把 K设置为thread名,V设置为looper吧

get方法 :


public T get() {
        // Optimized for the fast path.
        Thread currentThread = Thread.currentThread();
        Values values = values(currentThread);
        if (values != null) {
            Object[] table = values.table;
            int index = hash & values.mask;
            if (this.reference == table[index]) {
                return (T) table[index + 1];
            }
        } else {
            values = initializeValues(currentThread);
        }

        return (T) values.getAfterMiss(this);
    }

set方法 :

public void set(T value) {
        Thread currentThread = Thread.currentThread();
        Values values = values(currentThread);
        if (values == null) {
            values = initializeValues(currentThread);
        }
        values.put(this, value);
    }

哈哈,再见了,不足的地方咱们一起学习吧

发布了28 篇原创文章 · 获赞 22 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章