美文网首页
Handler消息机制源码分析

Handler消息机制源码分析

作者: 如愿以偿丶 | 来源:发表于2019-09-29 22:05 被阅读0次

    1.什么是Handler

    Handler是android中消息机制,Handler运行需要通过MessageQueue和Looper来支撑,Handler主要作用就是将一个任务切换到指定的线程中

    2 Handler使用

    发送三个消息,通过这三个来分析MessageQueue

    public class HandlerActivity extends AppCompatActivity {
        private TextView tv;
        private Handler mHandler = new Handler(){
            @Override
            public void handleMessage(@NonNull Message msg) {
                tv.setText(msg.obj + "");
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_handler);
            tv = findViewById(R.id.tv);
            //开启一个线程发送消息
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Message msg1 = Message.obtain();
                    msg1.obj = "姚明1";
                    mHandler.sendMessage(msg1);
    
                    Message msg2 = Message.obtain();
                    msg2.obj = "姚明2";
                    mHandler.sendMessageDelayed(msg2,1000);
    
                    Message msg3 = Message.obtain();
                    msg3.obj = "姚明3";
                    mHandler.sendMessageDelayed(msg3,500);
                }
            }).start();
        }
    }
    

    3.MessageQueue消息队列

    线程中更新 UI 的时候经常是调用 sendMessage() 和 sendMessageDelayed() ,看一下sendMessage() 方法

        //默认延时时间为0
        public final boolean sendMessage(@NonNull Message msg) {
          return sendMessageDelayed(msg, 0);
        }
        
        public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
           return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
        }
        
        public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
            ...
            return enqueueMessage(queue, msg, uptimeMillis);
        }
        
        private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
                long uptimeMillis) {
            //注意这里,msg.target绑定了我们的this也就是Handler
            msg.target = this;
            ....
            return queue.enqueueMessage(msg, uptimeMillis);
        }
    
    3.1MessageQueue的核心代码
        boolean enqueueMessage(Message msg, long when) {
    
            synchronized (this) {
                ....
                msg.when = when;
                Message p = mMessages;
                boolean needWake;
                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;
                }
    
                // We can assume mPtr != 0 because mQuitting is false.
                if (needWake) {
                    nativeWake(mPtr);
                }
            }
            return true;
        }
    

    通过上边的这些代码,我们暂时还没有看到 Handler 调用 handleMessage() 方法,但是有了一个重要的结论,我们每次发送一个消息都会被保存到了 MessageQueue 消息队列中,消息队列中采用的是单链表的方式。通过用下面这段代码发送消息,在 MessageQueue 中如图所示。

    3.2.MessageQueue内如图所示
        Message msg1 = Message.obtain();
        msg1.obj = "姚明1";
        mHandler.sendMessage(msg1);
        
        Message msg2 = Message.obtain();
        msg2.obj = "姚明2";
        mHandler.sendMessageDelayed(msg2,1000);
        
        Message msg3 = Message.obtain();
        msg3.obj = "姚明3";
        mHandler.sendMessageDelayed(msg3,500);
    
    在这里插入图片描述
    3.3 总结

       每次发送一个消息都会添加到消息队列中,按照when时间进行排序,消息队列采用的是单链表形式。

    4.Loop消息循环

    4.1 子线程中使用Handler

    先看一种现象,有时候我们像下面这么写会报错:

         new Thread(new Runnable() {
                @Override
                public void run() {
                    //子线程中使用Handler
                    Handler handler = new Handler();
                }
            }).start();
    
    在这里插入图片描述
    必须要这样写
        new Thread(new Runnable() {
            Override
            public void run() {
                //1.创建Looper对象,获取当前线程,通过当前线程获取ThreadLocalMap对象,保证一个线程只有一个Looper对象
                Looper.prepare();
                //2.获取当前的Looper对象,获取当前的MessagerQueue对象
                Handler handler = new Handler();
                //3.发送消息,将消息添加到消息队列中,通过msg.when来进行排序
                Message msg = Message.obtain();
                msg.obj = "姚明"
                handler.sendMessage(msg);
                //4.获取当前的Looper对象,获取当前的MessagerQueue对象,通过死循环不断获取MessageQueue中消息,回掉给Handler的handlerMessage。
                Looper.loop();
            }
        }).start();
    

    我们在主线程中从来没有调用过Looper.prepare();这行代码,为什么就不会报错呢。因为在我们程序入口ActivityThread中的入口函数 main() 已经帮我们调用了这行代码

        public static void main(String[] args) {
            //....省略部分代码
            
            Looper.prepareMainLooper();
    
            ActivityThread thread = new ActivityThread();
            thread.attach(false, startSeq);
    
            if (sMainThreadHandler == null) {
                sMainThreadHandler = thread.getHandler();
            }
            
            Looper.loop();
    
            throw new RuntimeException("Main thread loop unexpectedly exited");
        }
    
    4.2 Looper.prepare()分析

    我们来通过看源码来了解Looper.prepare()到底干了什么。

        //静态的
        static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    
        public static void prepare() {
            prepare(true);
        }
    
        private static void prepare(boolean quitAllowed) {
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            sThreadLocal.set(new Looper(quitAllowed));
        }
    
        /**
        *  1.获取当前线程,通过当前线程获取线程的ThreadLocalMap对象,一个线程只有一个ThreadLocal对象
        *  2.如果map不为空,就添加,key就是我们的sThreadLocal是静态的,value就是我们的Looper对象。
        *  3.如果map为空就会创建ThreadLocalMap
        */
        public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }
    
        //创建ThreadLocalMap
        void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }
    
        //创建MessageQueue,获取当前线程。
         private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            mThread = Thread.currentThread();
        }
    
    4.2.1 总结

       Looper.prepare() 就是创建了Looper对象,通过当前线程获取ThreadLocalMap,通过set来保证一个线程中只有一个Looper对象

    4.3 Looper.loop()解析
        public static void loop() {
            //1.获取当前线程的Looper对象
            final Looper me = myLooper();
            if (me == null) {
                throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
            }
            
            //2.获取消息队列
            final MessageQueue queue = me.mQueue;
    
            //3.死循环不断获取消息队列中的消息
            for (;;) {
                Message msg = queue.next(); // might block
                if (msg == null) {
                    // No message indicates that the message queue is quitting.
                    return;
                }
    
                try {
                    //msg.target就是我们的Handler,在MessageQueue中已经提到了msg.target绑定了我们的Handler,可以回去看一下
                    //3.通过 Handler 执行我们Message,这里边就调用我们的handleMessage方法
                    msg.target.dispatchMessage(msg);
                } finally {
                    if (traceTag != 0) {
                        Trace.traceEnd(traceTag);
                    }
                }
                //回收我们的消息
                msg.recycleUnchecked();
            }
        }
    
    
        /**
         * Handle system messages here.
         */
        public void dispatchMessage(@NonNull Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    //4.回掉我们的handleMessage
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    

    相关文章

      网友评论

          本文标题:Handler消息机制源码分析

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