安卓消息机制

来源:互联网 发布:当当网和淘宝网哪个好 编辑:程序博客网 时间:2024/05/11 20:31

理解:假如一个隧道就是一个消息队列,那么里面的每一辆汽车就是一个一个的消息(忽略超车等因素),即先进先出。

Looper:(相当于隧道),一个线程可以产生一个Looper对象,由它管理此线程里的MessageQueue。

Handler:(汽车)构建Handler对象来与Looper沟通,以便push新消息到MessageQueue或接收Looper(从MessageQueue取出)

所送来的消息。

MessageQueue:(车队,消息队列):用来存放线程放入的消息。

***给谁发消息就获得与谁Looper关联的Handler***


这些对象的一些伪代码实现:
class Message{
    Object obj;
    ......
}
class MessageQueue{
    LinkedBlockingQueue<Message> msgQ;
    ......
}
class Looper{一个线程一个
     MessageQueue msgQ;一个looper对应一个msgQ
     private Looper(){}
     public static void prepare(){}
     public static Looper myLooper(){}
     void loop(){}//负责迭代
}
class Handler{发送和处理消息
     public void sendMessage(Message msg){}
     public void handleMessage(Message msg){}
     .......
}


线程中使用Handler的步骤:

1、调用Looper的prepare()方法为当前线程创建Looper对象,创建Looper对象时,它的构造器会创建与之配套的MessageQueue。

2、有了Looper之后,创建Handler子类的实例,重写handleMessage()方法,负责处理来自于其他线程的消息。

3、调用Looper的loop()方法启动Looper。


下图供理解:



Android消息机制的宏观原理



先来看一张Android消息处理类之间的关系图



Android消息处理机制


我们从表象上解释一下原理,Handler负责将Message发送至当前线程的MessageQueue中,Looper时时刻刻监视着MessageQueue,将符合时间要求的Message取出,再带给发送消息的那个Handler通过HandleMessage处理。


对于消息机制的理解不能仅仅停留在这一步,下面我们从源码的角度分析一下具体的逻辑细节。



Android消息机制相关类的源码分析



其实写这篇文章之前,我就一直在思考,站在什么角度展开这个机制的描述,更容易让大家理解接受。思来想去,我觉得还是以一个Message游历的形式去描写,会显着有趣和清晰一点。


Message


人在边境X(子线程)服役的士兵Message慵懒得躺在一个人数为50(池中最大数量)的军营(Message池)中。不料这时突然接到了上司的obtain()命令(据说obtain命令更加节省军费),让他去首都(主线程)告诉中央领导一些神秘代码。小Message慌乱地整理了下衣角和帽子,带上信封,准备出发。


上司让士兵Message收拾完毕之后等待一个神秘人的电话,并且嘱咐他:到了首都之后,0是这次任务的暗号。



Message的创建和携带信息


Message是消息的载体,Message设计成为Parcelable类的派生类,这表明Message可以通过binder来跨进程发送。


通常我们都会用obtain()方法去创建Message,如果消息池中有Message有,则取出,没有,再重新创建。这样可以防止对象的重复创建,节省资源。



obtain方法源码


"铃铃铃..."小Message接到了一个陌生男子的电话。
“我叫handler,来自activity大本营,是你这次任务的接受者,一会我带你去首都的消息中心去报道。”


Handler


来自Activity大本营Handler部门是整个消息机制系统的核心部门,当然部门下有很多个 Handler,这次协助小Message任务的叫mHandler。Handler部门下的员工都有一个特点,就是只关心自己的message。


Handler属于Activity,创建任何一个Handler都属于重写了Activity中的Handler。



Activity中定义了Handler


在Handler的构造中,默认完成了对当前线程Looper的绑定,至于Looper是谁,一会再谈。



Handler的构造方法


通过Looper.myLooper()获取了当前线程保存的Looper实例,又通过mLooper.mQueue获取了Looper中的MessageQueue实例。在此时,mhandler实例与looper和messageQueue实例,关联上了。


mHandler神情骄傲得对小Message说:我已经跟首都的消息中心打好了招呼,准备接收你了,现在有两种车,一种车名叫“send”,一种叫“post”,你想坐哪辆去首都都可以,不过要根据你上司的命令,选择车种类下对应的型号哦~


  • send



  • post



从代码的实现上来看,post方法也是在使用send类的方法在发送消息,只是他们的参数要求是Runnable对象。


通过对Handler源码的分析,发现除了sendMessageAtFrontOfQueue方法之外,其余任何send的相关方法,都经过层层包装走到了sendMessageAtTime方法中,我们来看看源码:



sendMessageAtTime源码


这时小Message和mHandler一同上了车牌号为“sendMessage”的车,行驶在一条叫“enqueueMessage”的高速公路上,mHandler向一无所知的小Message介绍说,每个像他一样的Message都是通过enqueueMessage路进入MessageQueue的。我们是要去首都的MessageQueue中心,其实你的消息到时候也是我处理的,不过现在还不是时候哦,因为我很忙。



enqueueMessage源码


enqueueMessage是MessageQueue的方法,用来将Message根据时间排序,放入到MessageQueue中。其中msg.target = this,是保证每个发送Message的Handler也能处理这个Message。


Looper


路上的时间不短不长,mHandler依然为小Message热心介绍着MessageQueue和Looper


“在每个驻扎地(线程)中,只有一个MessageQueue和一个Looper,他们两个是相杀相爱,同生共死的好基友,Looper是个跑不死的邮差,一直负责取出MessageQueue中的Message”


"不过通常只有首都(主线程)的Looper和MessageQueue是创建好的,其他地方需要我们人为地创建哦~"



prepare方法


Looper类提供了prepare方法来创建Looper。可以看到,当重复创建Looper时,会抛出异常,也就是说,每个线程只有一个Looper。



Looper构造


紧接着在Looper的构造方法中,又创建了与它一一对应的MessageQueue,既然Looper在一个线程中是唯一的,所以MessageQueue也是唯一的。


在Android中,ActivityThread的main方法是程序的入口,主线程的Looper和MessageQueue就是在此时创建的。



ActivityThread的main方法


可以看到,在main方法中,既创建了Looper,也调用了Looper.loop()方法。


mHandler和小Message通过enqueueMessage路来到了MessageQueue中,进入之前,门卫仔仔细细地给小Message贴上了以下标签:
“mHandler负责带入”
“处理时间为0ms”
并且告诉小Message,一定要按照时间顺序排队。
进入队伍中,Looper大哥正在不辞辛劳的将一个又一个跟小Message一样的士兵带走。



loop方法


分析一下loop方法,有一个for的死循环,不断地调用queue.next方法,在消息队列中取Message。并且在Message中取出target,这个target其实就是发送消息的handler,调用它的dispatchMessage方法。


首都的MessageQueue中心虽然人很多,但是大家都井井有条的排着队伍,Looper老哥看了一眼手里的名单,叫到了小Message的名字,看了一眼小Message身上的标签,对他说:“喔,又是mHandler带来的人啊,那把你交给他处理了”


忐忑不安的小Message看到了一个熟悉的身影,mHandler就在面前,显然mHandler有些健忘,可能是接触了太多跟小Message一样的人,为了让mHandler想起自己,小Message说出了上司交给他的暗号0.



dispatchMessage方法


可以看见dispatchMessage方法中的逻辑比较简单,具体就是如果mCallback不为空,则调用mCallback的handleMessage()方法,否则直接调用Handler的handleMessage()方法,并将消息对象作为参数传递过去。

在handlerMessage()方法中,小Message出色的完成了自己的任务。


1 0