美文网首页
Handler机制详解

Handler机制详解

作者: Begank | 来源:发表于2017-06-18 15:31 被阅读0次

    前言

    handler是Android中独特的线程间通信方式.我们使用handler的经典模式是,在主线程中创建一个handler并重写其handlerMessage方法,然后在子线程中发送消息让handler进行处理.下面,就来看看这个handler里面到底是怎么实现的.
    @TODO:handler经典用法

    创建Handler

    //Handler的构造函数
    public Handler(Callback callback, boolean async) {
            .....代码省略...
           mLooper = Looper.myLooper();    //取出looper对象
            if (mLooper == null) {        //判断looper是否为空
                throw new RuntimeException(
                    "Can't create handler inside thread that has not called Looper.prepare()");//
            }
            mQueue = mLooper.mQueue;    //取出looper的MessageQueue对象
            mCallback = callback;
            mAsynchronous = async;
        }
    

    其中,myLooper()方法,最终调用了sThreadLocal.get()方法,从sThreadLocal中取出Looper.
    sThreadLocal是一个ThreadLocal对象,它可以保证每个线程中只有一个Looper对象.关于ThreadLocal具体可以参考这篇文章.

    public static @Nullable Looper myLooper() {
            return sThreadLocal.get();
        }
    

    接下来,判断mLooper对象是否为空,为空则抛出异常:"如果没有调用Looper.prepare()方法,则不能创建Handler"
    为什么呢?我们一般在主线程创建handler的时候,并没有调用过prepare方法,

    //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();
            }
        }
        private static void prepare(boolean quitAllowed) {
            .....代码省略....
            sThreadLocal.set(new Looper(quitAllowed));
        }
    //ActivityyThread 类
    public static final void main(String[] args) {
            SamplingProfilerIntegration.start();
           ……
            Looper.prepareMainLooper();
    }
    

    那为什么没有抛出这个异常呢?
    我们看到ActivityThread中,已经调用了looper.prepareMainLooper()方法创建一个looper对象并放到容器sThreadLocal中.
    另外,在创建looper的同时创建了一个消息队列.

    创建消息

    一般通过message.obtain(),从message pool中,取出复用的空消息,并给msg设置相应的数据obj,标识what,when等属性.
    message主要是对我们发送的消息进行此一次封装.

    handler发送消息到消息队列

    创建完消息后,我们会调用handler.sendMessage()方法,将消息发送到消息队列,而sendmessage方法最终调用enqueueMessage方法,
    首先调用msg.target = this;把当前的handler对象赋值给msg的target,这里就实现了handler与msg的绑定,后续在消息分发给handler处理的时候,就知道该由哪个handler来处理了.
    至于enqueueMessage方法,主要是将消息列表里面的第一条消息取出,进行时间的对比排序.

    public final boolean sendMessageAtFrontOfQueue(Message msg) {
            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, 0);
        }
        private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            msg.target = this;
            if (mAsynchronous) {
                msg.setAsynchronous(true);
            }
            return queue.enqueueMessage(msg, uptimeMillis);
        }
    

    Looper轮询器

    刚才在ActivityThread中,在Looper.prepareMainLooper()方法之后,还调用了Looper.loop()方法
    为什么突然讲到这个呢?我们将消息放到请求队列之后,需要调用looper的loop方法,不断从消息队列中取出消息,并分发给对应的handler来执行.

    public static void loop() {
            final Looper me = myLooper();
            ......
            final MessageQueue queue = me.mQueue;
            for (;;) {
                Message msg = queue.next(); // might block
                if (msg == null) {
                    return;
                }
                Printer logging = me.mLogging;
    
                msg.target.dispatchMessage(msg);//分发消息给对应的handler
        }
    //Handler类:
    public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);    //这里就是我们重写的handleMessage方法
            }
        }
    

    Loop()方法中的主要逻辑是不断从消息队列中取出消息,并将消息分发给对应的handler.
    然后会调用handler的dispatchMessage方法,处理消息.至此,全过程过程完成.
    注意了,当我们在子线程中创建handler时,除了需要手动调用Looper.prepare()方法之外,还需要调用Looper.loop()方法开启轮询.

    异步消息处理机制

    Handler进行消息处理的模式,总体来说如下:
    1.Handler发送消息到消息队列MessageQueue,并创建Looper开启轮询,
    2.Looper对象不停遍历MessageQueue,从消息队列中取出消息.分发给对应的handler
    3.handler获得消息后,调用handleMessage方法处理消息.

    扩展: HandlerThread

    @HydraTeam 出品 转载请注明出处

    相关文章

      网友评论

          本文标题:Handler机制详解

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