1.异步消息处理机制的概述
首先了解一下异步消息处理机制的概念,在异步消息处理的线程启动之后,会进入一个无限的循环中,每循环一次,就会从内部的消息队列中取出一条消息,然后回调相应的处理函数对该消息进行处理。如果消息队列中没有消息,那么线程就会阻塞,等待新的消息继续循环。
2.源码的解析
Looper、Handler、Message都参与了消息处理,下面对它们进行一一的分析。
1.Looper
Looper中主要就是prepare()和loop()这两个方法
先看一下prepare()方法
78行,调用Looper的构造方法,创建Looper对象,然后把一个Looper对象设置到TreadLocal里,75行判断ThreadLocal中的Looper对象是否为空,如果不为空则抛出异常。这也说明了prepare()方法只能调用一次。作用就是给当前线程设置一个Looper对象。
接着我们看下Loop的构造方法,在构造方法中,创建了一个MessageQueue(消息队列)对象;
下面我们看一下loop()方法(Run the message queue in this thread. Be sure to call)注释的意思大概是,使该线程的消息队列处于运行状态,确保调用结束循环。翻译起来很是拗口,下面我们一步步的分析。
110行,从sThreadLocal中获取Looper对象,如果为空,抛出异常(No looper...)当前线程没有Looper对象。说明了,loop()方法必须在prepare()方法之后执行。
114行,从Looper对象中取出消息队列对象(MessageQueue),上面提到了,Looper的构造方法调用的时候就创建了MessageQueue对象;
121行之后,就进入了我们说的无限循环中。
122行,从MsssageQueue中取出一条消息,接着判断如果消息为空,则线程进入阻塞状态(No message indicates that the message queue is quitting,没有消息,消息队列正在停止)。return,说明如果没有消息的时候,结束loop()方法。
135行,这里我们看到了取到了消息,并且调用了msg.target.dispatchMessage(msg);方法,字面上的大概意思就是把消息分发出去。具体怎么分发呢?msg.target 又是什么呢?其实msg.target就是Handler对象。下面我们会进行具体的分析。
152行,把消息分发出去之后,就把msg所占的资源释放掉。
先小结一下上面经历什么东西~在Looper中,首先调用了prepare方法,初始化了looper对象和meassageQueue对象,然后调用loop()方法,使线程进入了无限循环的状态,每循环一次就从MessageQueue对象中取出一条消息,然后调用msg.target.dispatchMessage(msg)方法对消息进行分发处理,然后释放消息所占的资源。如果取到的消息为空,即没有消息,那么就return掉loop()方法,线程进入阻塞状态。
上面需要注意的点是:
1.prepare()方法只调用一次,说明一个线程只有一个looper 对象,和一个messageQueue对象
2.loop()方法在prepare()方法之后调用。否则会抛出没有looper的异常。
2.Handler
上面提到了msg.target其实就是Handler对象,那么现在就对Handler进行分析。
同样先看下Handler的构造方法 :
198行,获取当前线程的Looper对象,
203行,获取Looper对象中的MessageQueue对象
从这里我们大概就知道Handler和MessageQueue能联系起来了。
接着我们看下我们平时发消息的时候常用的sendMessage(Message msg)方法:
依次点下去,我们找到了这个关键的地方
605行,获取MessageQueue对象,
612行,调用enqueueMessage方法,这个方法又是干什么用的呢?接着分析
有没有看到很关键的地方?
39行,把当前Handler对象this赋值给msg.target。 即,把Handler对象存到需要发送的消息(Msg)的targert里,然后把消息发送到MessageQueue队列中,这个时候,其实就是通过Handler发送消息,并且同时也把Handler发送消息者也一起发过去。这里我感觉特别有意思~这时候我们就应该清楚在loop()方法中,msg.target其实就是Handler对象。
现在我们知道了消息是怎么发到消息队列的,也知道怎么取出消息的。接着大家最关注的肯定就是msg.target.dispatchMessage()方法,拿到的消息,在Handler中怎么处理的。
好的,那下面我们就进入Handler中的dispatchMessage()方法(Handle system messages here)从字面上的意思可以理解为:在这里处理系统的消息。
02行,调用handleMessage()方法处理消息,我们看到handleMessage()方法是一个空方法,因为具体处理消息的逻辑,由我们自己去实现。这个时候,我们就可以对消息进行相应的处理~
我们继续针对以上的所有东西进行一个小结:
1.首先调用Looper.prepare() 方法,创建Looper和MessageQueue实例,并把MessageQueue保存到Looper中。注意,一个线程只能创建一个Looper实例,因此MessageQueue也只会有一个。
2.调用loop()方法,使本线程进入无限循环的状态,每循环一次都从MessageQueue取出一条消息,然后调用msg.target.dispatchMessage()方法,把消息分发到Handler中,进行处理。如果取出消息的为空,即没有消息了,那么loop()方法return掉,线程进入阻塞等待的状态。等到MessageQue中有消息的时候,继续进入无限循环的状态。
3.MessageQueue中的消息怎么来的呢?当我们调用handler.sendMessage()方法的时候,首先获取当前线程的looper对象,然后取出里面存的messageQueue对象,接着把消息存到了MessageQueue对象中。这个时候,消息队列MessageQueue中就会有消息了。注意,当调用handler.sendMesage()方法的时候,会把当前的Handler对象存到了msg.target里,跟着msg一起发送到了MessageQueue中,当轮询消息的时候,取出的消息,也会携带有Handler对象,这个时候就可以获取到Handler对象调用dispatchMessage方法进行对消息的处理了。
简单的来说,消息的发送和处理都是由Handler干的
4.有一点比较疑惑就是我们平时使用Handler的时候,并没有调用prepare()和loop()方法。其实在Activity启动的时候,已经在当前的UI线程中调用了prepare()和loop()方法;我们在ActivityTread中可以找到。
5.这里先抛出一个问题。在Looper的loop()方法中,进入无限的循环状态,当没有消息的时候,线程会进入阻塞的状态,理论上应该会造成ANR,为什么平时我们使用的APP没有看到这个现象呢?下一篇文章会专门讲解这个问题。
3.Message
Message就比较简单了,顾名思义就是用来存消息的对象。可以携带我们平时常用的数据结构。但是我们这里需要注意一些问题。创建一个Message对象,我们可以new 也可以调用 Message.obtain()方法创建,但是我建议是调用obtain()方法。因为Message 内部维护了一个Message池。用于Message的复用,避免每一次都new重新分配内存。
4.啰嗦一下
Handler的作用不仅仅是用于更新UI,我们可以在任何线程使用Handler发送消息,然后我们都能在创建Handler的线程中拿到消息,接着对消息进行处理。










网友评论