Android消息机制(Handler原理)-完全解析

作者: Yink_Liu | 来源:发表于2017-07-08 12:10 被阅读0次

    一 概述

    Handler主要被用来在子线程中访问UI线程,在ViewRootImpl中有一个checkThread()方法,对UI的操作都会有此验证。所以操作UI只能在主线程中进行。
    概念:
    Handler的运行由底层MessageQueue和Looper支撑。
    MessageQueue消息队列,单链表存储消息列表。它是消息的存储单元。
    Looper循环,它会无限循环查找是否有消息,有就处理掉。Looper创建一般被保存在TheadLoacal中。
    创建:
    Handler创建采用当前线程的Looper来构造消息循环系统。线程默认没有Looper
    主线程(UI线程)即:ActivityThread,主线程创建时会初始化Looper,所以主线程可直接使用Handler

    二 运行机制

    2.1 TheadLoacal

    TheadLoacal的用来保存数据,以线程作用域,不同线程具有不同的数据副本。
    以一个例子来简单粗暴的说明:

    //定义一个Integer泛型的ThreadLocal
    private ThreadLocal<Integer> mIntTheadLocal = new ThreadLocal<Integer>();
    
    mIntTheadLocal.set(0);
    Log.d("yink","UI Thead, mIntTheadLocal = " + mIntTheadLocal.get());//UI线程
    
    new Thread("thead 1") {
        @Override
        public void run() {
            mIntTheadLocal.set(1);
            Log.d("yink","thead 1, mIntTheadLocal = " + mIntTheadLocal.get());//线程1
        }
    }.start();
    
    new Thread("thead 2") {
        @Override
        public void run() {
            Log.d("yink","thead 2, mIntTheadLocal = " + mIntTheadLocal.get());//线程2
        }
    }.start();
    

    mIntTheadLocal是同一个对象,我们分别在UI线程、线程1和线程2中对其进行set,get并打印Log如下:

    07-06 23:24:33.151 12661-12661/com.example.android.myapplication D/yink: UI Thead, mIntTheadLocal = 0
    07-06 23:24:33.153 12661-16454/com.example.android.myapplication D/yink: thead 1, mIntTheadLocal = 1
    07-06 23:24:33.154 12661-16455/com.example.android.myapplication D/yink: thead 2, mIntTheadLocal = null
    

    由于TheadLoacal的特性,它其中之一的功能就是被用来保存Looper对象

    2.2 MessageQueue

    MessageQueue,单链表数据结构,主要包含两个操作:插入(enqueueMessage)和读取(next)
    先看enqueueMessage,它之做了单链表插入数据操作

    boolean enqueueMessage(Message msg, long when) {
        ...
        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 {
            // Inserted within the middle of the queue.  Usually we don't have to wake
            // up the event queue unless there is a barrier at the head of the queue
            // and the message is the earliest asynchronous message in the queue.
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
        //单链表插入数据操作。
            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;
        }
        ...
    }
    

    再看next,查询到msg后,移除这个msg,并返回这个msg

    Message next() {
            ...
        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;
            //msg不为空,移除msg
            if (prevMsg != null) {
                prevMsg.next = msg.next;
            } else {
                mMessages = msg.next;
            }
            msg.next = null;
            if (DEBUG) Log.v(TAG, "Returning message: " + msg);
            msg.markInUse();
            //返回msg
            return msg;
            }
        } else {
            // No more messages.
            nextPollTimeoutMillis = -1;
        }
            ...
    }
    

    2.3 Looper

    Looper作用:不停的从MessageQueue中查询是否有消息,有就处理,没有就一直阻塞。
    我们先来一个demo,为子线程创建Looper,来理解Looper的作用:

    //主线程中定义
    private Handler mHandler;
    
    new Thread("Thread 1") {
        @Override
        public void run() {
            //创建Looper
            Looper.prepare();
            //在Thread 1中创建Handler
            mHandler =  new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    Bundle b = new Bundle();
                    b = msg.getData();
                    Log.d("yink","receive the number = " + b.getInt(KEY));
                    switch (b.getInt(KEY)) {
                        case 3:
                            //子线程处理完事情后,退出循环
                            //Looper还提供一个quitSafely(),这个方法是设置标记位,把队列中消息处理完后再退出。
                            getLooper().quit();
                            break;
                        default:
                            break;
                    }
                    super.handleMessage(msg);
                }
            };
            //循环,关键函数
            Looper.loop();
        }
    }.start();
    
    new Thread("Thread 2") {
        @Override
        public void run() {
            for (int i = 0 ; i < 5 ; i++) {
                Message msg = new Message();
                Bundle b = new Bundle();
                b.putInt(KEY,i);
                msg.setData(b);
                //如果线程1的run没执行的话,mHandler还是null,所以加个判断
                if (mHandler != null) {
                    Log.d("yink","send key i = " + i);
                    //发送消息
                    mHandler.sendMessage(msg);
                } else {
                    Log.d("yink","mHandler is null, i = " + i);
                }
                SystemClock.sleep(1000);
            }
        }
    }.start();
    

    结果如下:

    07-07 02:29:24.219  1151 12404 D yink    : send key i = 0
    07-07 02:29:24.220  1151 12403 D yink    : receive the number = 0
    07-07 02:29:25.221  1151 12404 D yink    : send key i = 1
    07-07 02:29:25.223  1151 12403 D yink    : receive the number = 1
    07-07 02:29:26.223  1151 12404 D yink    : send key i = 2
    07-07 02:29:26.223  1151 12403 D yink    : receive the number = 2
    07-07 02:29:27.225  1151 12404 D yink    : send key i = 3
    07-07 02:29:27.226  1151 12403 D yink    : receive the number = 3
    07-07 02:29:28.227  1151 12404 D yink    : send key i = 4
    07-07 02:29:29.231  1151 12404 D yink    : send key i = 5
    

    ActivityThread中的Looper比较特殊,它的创建是:prepareMainLooper(),获得:getMainLooper,可在任何地方获取到主线程的Looper

    接下来我们来看Looper中最重要的loop()方法:

    public static void loop() {
            ...
        
        for (;;) {
            //无限循环获取queue.next(),由前面描述的MesageQueue的next方法,只有获取到消息才会返回,否则一直会阻塞,所以looper也会在这里阻塞
            Message msg = queue.next(); // might block
            if (msg == null) {
            // No message indicates that the message queue is quitting.
            //只有当Looper调用退出后,queue.next()才会返回null,因为不退出,MesageQueue会阻塞在那儿一直查询
            //此无限循环中,只有当msg == null才退出循环
            return;
            }
        ...
        try {
                    //target实际就是Handler,所以最终调用到创建Handler线程中去。
                    msg.target.dispatchMessage(msg);
                } 
        ....
    

    2.4 Handler

    Handler主要也是两个动作:发送和接收
    先看发送:

    public final boolean sendMessage(Message msg){
        return sendMessageDelayed(msg, 0);
    }
    
    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }
    
    public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
    }
    
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
    

    发送过程最后调用到了enqueueMessage,最后是向队列中插入了一条消息。
    最后通过Looper返回给了Handler的dispatchMessage,转向接收处理。

    public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    

    第一种接收if (msg.callback != null) :
    如果msg.callback != null成立,则调用handleCallback(msg)来处理

    private static void handleCallback(Message message) {
            message.callback.run();
        }
    

    这个callback其实就是Handler.post中的runable
    post过程如下:

    public final boolean post(Runnable r)
        {
           return  sendMessageDelayed(getPostMessage(r), 0);//调用getPostMessage
        }
    
    private static Message getPostMessage(Runnable r) {
            Message m = Message.obtain();
            m.callback = r;//把post中的Runnable赋值给msg.callback
            return m;
        }
    

    证实:

            new Thread("Thead 1") {
                @Override
                public void run() {
                    Looper.prepare();
                    mHandler =  new Handler(){
                @Override
                        public void handleMessage(Message msg) {
                Log.d("yink","handleMessage ");
                            super.handleMessage(msg);
                }
    
                        @Override
                        public void dispatchMessage(Message msg) {
                            Log.d("yink","dispatchMessage ");
                            super.dispatchMessage(msg);
                        }
                    };
                    Looper.loop();
                }
            }.start();
    
            new Thread("Thead 2") {
                @Override
                public void run() {
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            Log.d("yink","post runable");
                        }
                    });
                }
            }.start();
    

    log如下,先是调用那个dispatchMessage然后走到调用了message.callback.run();

    07-07 03:42:43.862 10475 10515 D yink    : dispatchMessage 
    07-07 03:42:43.862 10475 10515 D yink    : post runable
    

    第二种接收else:
    如果 if (mCallback != null) 则调用mCallback.handleMessage(msg)
    这里的mCallBack为:

    public interface Callback {
            public boolean handleMessage(Message msg);
        }
    
    //Handler的一个构造函数
    public Handler(Callback callback) {
            this(callback, false);
        }
    

    可以在创建Handler的时候传递进来,这样就可以回调监听。就是一个接口回调,这里就不举例了。

    如果mCallback == null就调用handleMessage,在源码中handleMessage是一个空函数,可以继承Handler实现handleMessage方法来进行监听。Looper中的demo就是实现handleMessage方法实现监听的。也可继承Handler实现,道理相同

    //Handler中的handleMessage方法,一个空函数
    public void handleMessage(Message msg) {
    }
    

    总结

    Android的消息机制整体来说也就是Handler的消息机制,Handler、Looper和MessageQueue三者结合,实现了线程间的通信。明白这种机制,使用更加如鱼得水。

    Read the fucking source code!

    相关文章

      网友评论

        本文标题:Android消息机制(Handler原理)-完全解析

        本文链接:https://www.haomeiwen.com/subject/jewdhxtx.html