Análise de código-fonte do mecanismo de mensagem de 4 manipuladores

    O Handler é um mecanismo de retorno de chamada assíncrono fornecido pelo Android. Ele realiza principalmente a comunicação entre threads de mensagens. Então surge a pergunta. Por que precisamos do Handler? Há dois motivos principais. Um é evitar operações demoradas que bloqueiam o thread principal ( incluindo solicitações de rede). IU travada ou ANR, o sistema Android exige que o usuário coloque essas operações no subthread, 2 O Android também exige que a IU não possa ser atualizada no subthread (estimado com base em problemas de segurança do thread ), isso requer um mecanismo, no sub-thread A mensagem é passada para o thread principal no thread, então há um Handler.

    Para implementar o callback assíncrono, não basta ter o Handler sozinho. O Android também fornece Looper, Message e MessageQueue. Essas classes juntas realizam a função de callback assíncrono. Normalmente, instanciamos um objeto Handler mHandler diretamente na Activity, enviamos uma mensagem através de mHandler na thread filha, e então recebemos o método de processamento no método callback passado ao instanciar o Handler. fio. Portanto, começamos a instanciar o Handler para uma análise aprofundada.

1, comece a instanciar o Handler

1,在主线程实例化Handler
private Handler mHandler=new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            return false;
        }
    });

2,进入Handler内部实现,到了最终的构造方法中

   public Handler(@Nullable Callback callback, boolean async) {
        ...
        mLooper = Looper.myLooper();//取出保存好的Looper
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;//取出Looper中的消息队列
        mCallback = callback;   //后面处理消息的回调
        mAsynchronous = async;
    }

3,取出保存好的Looper的过程
   public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

4,ThreadLocal是什么,起的作用是什么?具体的看下ThreadLocal中set/get()的实现
ThreadLocal.java

  ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

    public void set(T value) {
        Thread t = Thread.currentThread();//当前线程
        ThreadLocalMap map = getMap(t);//得到线程中的一个变量,作用类似于HashMap,可以通过k-v保存数据
        if (map != null)
            map.set(this, value);       //map以ThreadLocal为key,以Looper为value
        else
            createMap(t, value);        //创建一个以ThreadLocal为key,以Looper为value的map给thread
    }

   public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);//取出map中的value,也就是looper
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

所以,Looper中的sThreadLocal明着像是一个保存looper的容器,但实际却是自己为key,looper为value,保存在线程Thread中的map中

2. Depois de instanciado o Handler, vemos que o Looper e o MessageQueue são retirados internamente, pelo que é necessário saber como estes são gerados

1,在主线程中取出来的,那肯定是在主线程实例的,而且是在主线程(ActivityThread)刚启动的时候

ActivityThread.java
   public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();//重点1
        ...
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);//这里之前详细分析过了,主要为了application/activity的创建和启动
        ...
        Looper.loop();//重点2

        throw new RuntimeException("Main thread loop unexpectedly exited");//抛异常, 主线程的loop出乎意料的退出了
    }

2,重点1,Looper是如何产生的?
    Looper.java
   public static void prepareMainLooper() {
        prepare(false);//关键语句,实例一个Looper,并保存
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();//实例化的Looper赋给sMainLooper
        }
    }   

  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));//通过threadLocad保存new出来的Looper
    }

 public static @Nullable Looper myLooper() {
        return sThreadLocal.get();//取出来
    }

3,重点2 Looper是如何工作的?
     public static void loop() {
        final Looper me = myLooper();
        ...        
        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;
            }
            msg.target.dispatchMessage(msg);
        ...
        }
    }


简化以后就很明了了,loop()中取出之前实例好的looper,并取出looper中的消息队列queue,开启死循环,不停的执行消息队列取消息操作,
message.target是私有变量handler

Handler.java

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {//一般常见于使用handler.postXX(Runnable)发送的消息
            handleCallback(msg);
        } else {
            if (mCallback != null) {这是之前实例化Handler传进去的回调监听类
                if (mCallback.handleMessage(msg)) {//回调类的处理方法,实际在activity上,这样就把消息队列的消息传到主线程上了
                    return;
                }
            }
            handleMessage(msg);//如果实例化Handler未传入回调类,则必须重新Handler本身的HandleMessage()方法,就是这个方法,同样的,把消息传到主线程上了
        }
    }

小结:通过查看Looper的实例化和Looper.loop()的调用,我们清楚的看到了消息的处理流程,
loop()依次从messageQueue中取出message,然后从message中取出handler去分配处理消息。

3. Agora que a mensagem foi retirada da fila de mensagens, deve haver um processo de colocar a mensagem na fila de mensagens

1,通过handler发送message的方法有2类,一种是send->Message系列,一种是post->Runnable系统

方法中带Message参数    
sendMessage()//常用
sendMessageDelayed()//延迟接收的消息
sendMessageAtTime()//准确时间接收的消息
sendMessageAtFrontQueue()//见名知义,放到消息队列最前面,也就是马上执行的消息
sendEmptyMessage()//空消息
sendEmptyMessageAtTime()
sendEmptyMessageDelayed()

方法中带Runnable参数,通过getPostMessage()生成Message,runnable参数传入到message中(处理消息时使用此回调)
post()
postDelayed()
postAtTime()
postAtFrontOfQueue()

private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

上面所有发送消息的方法,最终都是通过sendMessageAtTime(Message msg, long uptimeMillis)来发送的(方法千千万,最终汇总),uptimeMillis为处理消息的时间    


 public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;//这是Looper中的消息队列
        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) {
        msg.target = this;//this就是当前的handler,处理消息时就是用的msg中的target
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);//最终,handler把消息送到了消息队列中,然后消息队列进行入队操作
    }

4. Bata os tambores e passe as flores, a mensagem finalmente será enviada para a fila de mensagens

0,在消息message进入消息队列messagequeue之前,我们需要对Message和MessageQueue的基本结构有初步的了解,方便了解入队的整个过程
Message:有个when字段,表示当前消息处理的时间,同样的,message关联指向了另一个message,字段名为next,所以,整个Message可以组成一个链表结构
MessageQueue:消息队列管理保存着消息,因为Message可以组成一个链表结构,所以MessageQueue只需要持有一个Message对象就能完成对Message的保存和管理,
因为消息队列有处理时间的要求,所以消息队列持有的头消息必定是最早处理的(when最小),所以在入队的过程就必然需要有对时间的比较。

1,enqueue的就是入队的意思
boolean enqueueMessage(Message msg, long when) {
        ...

        synchronized (this) {
           ...

            msg.markInUse();
            msg.when = 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;                            //头消息变成msg的next消息,这样就当前消息变成了头消息,原先的头消息变成第二个消息对象
                mMessages = msg;                        //msg赋值给消息对象持有的头消息
                needWake = mBlocked;                    //不需要唤醒,这个变量后面再讨论
            } else {                                    //下面的操作是msg要插入到消息链表中间去

                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;//临时变量
                for (;;) {//死循环遍历消息链表,查找msg需要插入的位置
                    prev = p;//当前查找的消息放到prev上,第一次当然是消息队列持有的头消息
                    p = p.next;//取出下一个消息为p   此时 prev->p
                    if (p == null || when < p.when) {//如果下一个消息为空(到链表尾巴上了) 或者时间戳小于下一个消息的时间戳 则位置找到了
                        break;//跳出死循环,位置找到了,msg要插在p前面,此时prev->p,执行插入后期望的顺序为 prev->msg->p
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p;   //
                prev.next = msg;//这2步实现的功能就是链表顺序变为 prev->msg->p 此时头消息还是mMessage,但msg已经到它的链表上了
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);       //有消息来了,底层唤醒Looper
            }
        }
        return true;
    }

2,这样就很明了了,发送的消息经过比较和插入,终于进入到消息链表中了,结合前面的Looper.loop(),这样,整个流程就清楚了。

Resumo: O processo geral é o seguinte: No estágio inicial da criação do thread principal (ActivithThread.man()), enquanto o Looper é criado, uma fila de mensagens MessageQueue é criada no método de construção do Looper e o Looper é chamado após main( ). loop(), loop() chamará o Messagequeue instanciado no Looper, obterá continuamente a Message por meio de queue.next() e, em seguida, agendará e processará a mensagem por meio do destino (ou seja, o Handler) definido pela mensagem , e também podemos usar a instância Uma série de métodos send/post do Handler otimizado para enviar mensagens para a fila de mensagens. Pegue uma castanha na realidade:

Enquanto a estação de metrô estiver funcionando normalmente, as máquinas que passaram na inspeção de segurança devem estar ligadas e funcionando. A estação de metrô pode ser comparada a ActivityThread, a máquina de inspeção de segurança é Looper e o equipamento de inspeção de segurança está funcionando continuamente ( chamando Looper.loop()). O equipamento de inspeção de segurança possui uma correia de transmissão ( MessgaQueue), cada bagagem (Message) deve ser colocada na correia transportadora, o processo de colocação é o send/post() do handler, após a bagagem é testada e não há problema, ela pode ser retirada da outra ponta (handler.dispatchMessage(message)), Se a operação handler.send/post() for executada em outro thread, quando a mensagem for recuperada e programado para processamento, ele já está no thread principal, que realiza o retorno de chamada assíncrono.

 

O princípio de funcionamento do Handler é mais ou menos como mostrado na figura

Desta forma, todo o fluxo de trabalho do Handler é resolvido.

Claro, quando se trata de loops infinitos, por que looper.loop() não causa bloqueio de thread devido a loops infinitos?

答案很简单,整个App因为主线程中loop.looper()的死循环而保持活动,如果跳出死循环,整个App会抛异常,
ActivityThread.main(){
...
    Looper.loop();//重点2
   throw new RuntimeException("Main thread loop unexpectedly exited");//抛异常, 主线程的loop出乎意料的退出了 这句话正常情况下不会被执行
}
而且,造成主线程堵塞是因为对Message处理的超时造成的,以之前举例说明,安检设备因为传输带不断循环而保持正常工作,一旦行李过重,用户从传送带上搬离行李过慢才会造成后续行李的卡住(各类事件不被处理,造成阻塞)。
同样的,在消息队列中没有消息时,主线程会进入休眠状态,即消息队列执行next()方式时,会根据下一个消息还有多久执行系统底层方法nativePollOnce()释放资源进入休眠状态
        MessageQueue.next(){
             for (;;) {
                if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);//直到下条消息到达或者有事务发生,
        }

而一旦有最新消息事件进入到消息队列时,一旦新事件需要马上执行或者到了执行时间的时间,会通过系统底层方法nativeWake()唤醒主线程进行工作
        MessageQueue.enqueueMessage(){

        ...
          if (needWake) {
                nativeWake(mPtr);//通过往 pipe 管道写端写入数据来唤醒主线程工作,这里采用的 epoll 机制
            }
        }

O mecanismo sleep executado pela thread principal quando não há tarefas otimiza muito o desempenho, assim como no envio de mensagens, o uso de get é mais eficiente que as instâncias diretas.

1,Message.java

  /**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     *从全局池中返回一个新消息实例
     */
 public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;//Message类内部也有一个消息头,相当于也有一个消息链表 头消息置于m
                sPool = m.next;     //下一个消息置为表头 
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;//
                return m;//返回当初的表头消息
            }
        }
        return new Message();
    }

这样的话也不用每次都实例消息,最大限度的提高效率。
Resumo: Como um mecanismo de retorno de chamada de mensagem, Handler envolve relativamente poucas classes associadas e a estrutura geral é relativamente clara, mas a lógica interna ainda é muito valiosa para aprender.

Acho que você gosta

Origin blog.csdn.net/sunguanyong/article/details/127861061
Recomendado
Clasificación