美文网首页android
Handler机制到底是个什么东西?(一句话说清楚)

Handler机制到底是个什么东西?(一句话说清楚)

作者: 高达一号 | 来源:发表于2019-03-23 21:08 被阅读61次

    “说一下handler机制”,这句话面试的时候被问过无数次。但是到底要怎么说,网上却没有一个标准答案,很多人洋洋洒洒一大篇加各种图,实在让人望而生畏,你是让我面试的时候背这么一大篇吗?

    其实真的没有那么复杂,干货上前,标准答案:

       Handler机制主要由Handler,Looper,MeesageQueue组成。
       Looper在程序启动时即创建并不断的在循环,直到Handler有消息发送到MessageQueue时,
       Looper取出消息且回调给Handler来处理。
    

    怎么样,洋洋洒洒一大篇看不懂,这么几句话,是不是简单多了?

    什么,你说不够深入?

    好吧,那我们来深入一下,《How to read a book》讲,一定要提出问题,那我们就来深入的提出几个问题:

    1.Looper是个什么玩意,它是怎么创建的?它是什么时候开始循环的?

    2.Handler是怎么把发送消息让Looper知道的?

    3.Looper又是怎样取出消息且回调给Handler来处理的?

    在这里,我们必须阅读一下源码了,我们来看这三个主要组成的其一Looper类,打开代码,是不是很长一大片不知道怎么入手?哎呀好困难怎么办。答案是,一点也不困难,因为我们阅读源码,并不是一行一行读,而是只要看核心方法就够了,什么是核心方法呢?Looper有俩个,prepare(),这个单词的意思是准备;还有一个loop(),这个单词的意思是循环。

    我们来看perpare()

        static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
        final MessageQueue mQueue;
        final Thread mThread;
    
        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));
        }
        
        private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            mThread = Thread.currentThread();
        }
    

    是的没有错,就这些了,我们可以看到它做了三件事情:
    第一、“sThreadLocal.set(new Looper(quitAllowed));” 把new出来的Looper给塞到ThreadLocal里面,我们不难理解ThreadLocal就是一个类似HashMap的东东;
    第二、“ mQueue = new MessageQueue(quitAllowed);” new了一个MessageQueue;
    第三、“mThread = Thread.currentThread();” 获取当前线程的引用。

    接下来是loop()

       public static void loop() {
            final Looper me = myLooper();
            if (me == null) {
                throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
            }
            final MessageQueue queue = me.mQueue;
            for (;;) {
                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 {
               
                }
                msg.recycleUnchecked();
            }
        }
    

    把不重要的代码删掉,是不是一目了然了,已经不用多解释了吧?

    我们再来看一个类,ActivityTread的main[]方法,这个地方是程序启动时就会调用的

        public static void main(String[] args) {
            Looper.prepareMainLooper();
            Looper.loop();
            throw new RuntimeException("Main thread loop unexpectedly exited");
        }
    
        class Looper{
          public static void prepareMainLooper() {
            prepare(false);
            synchronized (Looper.class) {
                if (sMainLooper != null) {
                    throw new IllegalStateException("The main Looper has already been prepared.");
                }
                sMainLooper = myLooper();
            }
        }
    }
    

    一目了然,也就是说,程序启动时,先prepare() new出来一个Looper,并且把它塞到ThreadLocal里面,以后在同一个线程要用的时候都从里面拿,避免创建多个Looper,然后就开始了loop(),死循环之路,也就是说程序无时无刻不在loop(),然后msg=null的时候,return,直到发现有了msg,msg.target.dispatchMessage(msg);交给msg的target,也就是handler来处理。

    我们再来看下Handler的源码,我们先看Handler的构造函数

        public Handler(Callback callback, boolean async) {
            mLooper = Looper.myLooper();
            if (mLooper == null) {
                throw new RuntimeException(
                    "Can't create handler inside thread that has not called Looper.prepare()");
            }
            mQueue = mLooper.mQueue;
        }
    

    Looper.myLooper,正是我们刚才说的,从ThreadLocal里面拿出本线程已有的Looper,然后MessageQueue,也是原来Looper里面的那个MessageQueue,接下来是Handler发送消息的方法,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);
        }
        private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            return queue.enqueueMessage(msg, uptimeMillis);
    }
    

    不难理解,Handler并没有真正意义的去“发送”,而是把消息放到了MessageQueue中而已。

    最后,我们来看下Handler如何处理的消息,dispatchMessage

        public void handleMessage(Message msg) {
        }
        /**
         * Handle system messages here.
         */
        public void dispatchMessage(Message msg) {
                handleMessage(msg);
        }
    

    还记不记得,Loop.loop()中,一旦发现MessageQueue有值,就会调用msg.target.dispatchMessage(msg);走的就是这里啦,还记不记得我们平时写Handler的时候,一般都是这样

         Handler mHandler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                
                }
            };
    

    重写的就是上面这个方法啦,至此,我们来回顾一下上面三个问题:

    1.Looper是个什么玩意,它是怎么创建的?它是什么时候开始循环的?

    2.Handler是怎么发送消息让Looper知道的?

    3.Looper又是怎样取出消息且回调给Handler来处理的?

    如果对照源码仔细看了本文,相信这几个问题已经不难啦,而且你也学会了如何真正的阅读源码,那就是抓住主线而忽略掉不重要的部分,如果对你有帮助,点个喜欢吧!

    相关文章

      网友评论

        本文标题:Handler机制到底是个什么东西?(一句话说清楚)

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