现在的位置: 首页 > 综合 > 正文

进程(一) 1.4Android中异步处理大杀器——Handler(3),Looper,Message,MessageQueue

2013年08月14日 ⁄ 综合 ⁄ 共 3423字 ⁄ 字号 评论关闭

介绍下handler运用中用到的相关类:Looper,Message ,MessageQueue 


Looper

Looper类用来创建消息队列. 每个线程最多只能有一个消息队列,android中UI线程(一般指主线程)默认具有消息队列,但非UI线程在默认情况下是不具备消息队列的(这也很好的说明了,前面文章说的,只有在主线程可以直接创建handler对象,而在别的线程需要有looper对象才可以使用handler发送消息,因为他们自身不带有消息循环和消息队列)。 如果需要在非UI线程中开启消息队列,
需要调用Looper.prepare()方法
, 在该方法的执行过程中会创建一个Looper对象, 而Looper的构造函数中会创建一个MessageQueue instance(Looper的构造函数是私有的, 在Looper类之外无法创建其对象)。 此后再为该线程绑定一个Handler instance, 然后调用Looper.loop()方法, 就可以不断的从消息队列中取出消息和处理消息了。Looper.myLoop()方法可以得到线程的Looper对象,
如果为null, 说明此时该线程尚未开启消息队列。

a> 创建一个 Looper 对象时,会同时创建一个 MessageQueue 对象(一个looper对应一个MessageQueue)

b> 除了主线程有默认的 Looper ,其他线程默认是没有 MessageQueue 对象的,所以,不能接受 Message 。如需要接受,自己定义 一个 Looper 对象 ( 通过 prepare 函数 ), 这样该线程就有了自己的 Looper 对象和 MessageQueue 数据结构了。  
c> Looper 从 MessageQueue 中取出 Message 然后,交由 Handler 的 handleMessage 进行处理。处理完成后,调用 Message.recycle() 将其放入 Message Pool 中。


Message 

Message :消息对象, Message Queue 中的存放的对象。一个 Message Queue 中包含多个 Message 。 Message 实例对象的取得,通常使用 Message 类里的静态方法 obtain(), 该方法有多个重载版本可供选择;它的创建并不一定是直接创建一个新的实例,而是先从 Message
Pool( 消息池 ) 中看有没有可用的 Message 实例
,存在则直接取出返回这个实例。如果 Message Pool 中没有可用的 Message 实例,则才用给定的参数创建一个 Message 对象。调用 removeMessages() 时,将 Message 从 Message Queue 中删除,同时放入到 Message Pool 中。除了上面这种方式,也可以通过Handler 对象的 obtainMessage() 获取
一个 Message 实例
(其实这个也是调用Message的obtain方法,这个会在后面的源码中解释)。

Message类用于表示消息. Message对象可以通过arg1, arg2, obj字段和setData()携带数据, 此外还具有很多字段.
when字段决定Message应该何时出对处理;
target字段用来表示将由哪个Handler对象处理这个消息;
next字段表示在消息队列中排在这个Message之后的下一个Message;
callback字段如果不为null表示这个Message包装了一个runnable对象;
what字段表示code, 即这个消息具体是什么类型的消息. 每个what都在其handler的namespace中, 我们只需要确保将由同一个handler处理的消息的what属性不重复就可以.


MessageQueue 

MessageQueue类用于表示消息队列. 队列中的每一个Message都有一个when字段, 这个字段用来决定Message应该何时出对处理。消息队列中的每一个Message根据when字段的大小由小到大排列, 排在最前面的消息会首先得到处理, 因此可以说消息队列并不是一个严格的先进先出的队列
主线程创建时,会创建一个默认的 Looper 对象,而 Looper 对象的创建,将自动创建一个 Message Queue 。其他非主线程,不会自动创建 Looper ,要需要的时候,通过调用 prepare 函数来实现(这个可以查阅Looper中的说明)。

将消息压入消息队列:
Message对象的target字段关联了哪个线程的消息队列, 这个消息就会被压入哪个线程的消息队列中.

a >调用Handler类中以send开头的方法可以将Message对象压入消息队列中;
     调用Handler类中以post开头的方法可以将一个runnable对象包装在一个Message对象中, 然后再压入消息队               列, 此时入队的Message其callback字段不为null, 值就是这个runnable对象. 调用Handler对象的这些方法入队              的Message, 其target属性会被赋值为这个handler对象.

b >调用Message对象的sendToTarget()方法可以将其本身压入与其target字段(即handler对象)所关联的消息队列               中. 

从消息队列中取出消息并处理消息:
所有在消息队列中的消息, 都具有target字段. 消息是在target所关联的线程上被取出和处理的.
a > 如果取出的Message对象的callback字段不为null, 那么就调用callback字段的run()方法(callback字段的类型是runnable).注意此时并不开启一个新的线程运行run()方法, 而是直接在handler对象(即Message的target字段)所关联的线程上运行(其实是有系统自动产生了一个线程,这样才会异步)
b > 如果取出的Message对象的callback字段为null, 且Handler对象中的callback字段也为null, 那么这个消息将由Handler对象的handleMessage(msg)方法处理. 注意Message对象的callback字段是Runnable类型的而Handler对象的callback字段是Callback类型的,
Handler对象的callback字段是在创建Handler instance的时候指定的, 如果没有指定则这个字段为null, 详见Handler类的四个构造方法.
c> 如果取出的Message对象的callback字段为null, 且Handler对象中的callback字段不为null, 那么这个消息将由Handler对象中的callback字段的handleMessage方法处理.


注:

1.如果想在非ui线程中新建Handler对象,这时需要使用调用Looper的prepare()来产生looper对象,而创建looper对象的时候会创建相应的消息队列;

2.一个线程只有一个消息循环looper,这样也就说明只有一个消息队列;但是可以有多个handler,那么如何区分消息发送给谁处理呢??每个消息中都有target记录每个handler;

3.通过looper中的函数loop()可以死循环消息;

4.获取消息的对象的时候,最好不要自己创建,而是使用Message.Obtain(),从消息池中获取;

4.消息队列不是一个严格意义的消息队列,他是按message的when进行排序的;

5.至于post和send已经在1.3 Android中异步处理大杀器——Handler(2)说明过了;

5.消息处理的三种情况:

a>通过post发送的消息,Message对象的callback字段不为null,且是callback(runable对象),则会在runable的run()中处理消息;

b>通过send发送消息,Message对象的callback字段为null, 且Handler对象中的callback(handler的接口,是Callback类型)字段也为null,则给handler的handMessage()处理;

c>Message对象的callback字段为null, 且Handler对象中的callback字段不为null,将由Handler对象中的callback(handler的接口,是Callback类型)的handMessage()处理;


抱歉!评论已关闭.