`
夏文权
  • 浏览: 236340 次
  • 性别: Icon_minigender_1
  • 来自: 贵州
社区版块
存档分类
最新评论

Android 消息机制(Handler,Looper,MessageQueue,Message)

 
阅读更多
写道
转载
android的消息处理有三个核心类:Looper,Handler和Message。其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,Handler扮演了往MQ上添加消息和处理消息的角色(只处理由自己发出的消息),即通知MQ它要执行一个任务(sendMessage),并在loop到自己的时候执行该任务(handleMessage),整个过程是异步的。

消息处理过程如下图所示:

Handler主要涉及到的内容有:

  Handler 、 Handler.Callback、AsyncQueryHandler

  Looper、

  HandlerThread、Runnable

  Message、Message queue

如下图所示:

Looper

Android官方文档中Looper的介绍:

Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.

Most interaction with a message loop is through the Handler class.

This is a typical example of the implementation of a Looper thread, using the separation of prepare() and loop() to create an initial Handler to communicate with the Looper.

View Code
class LooperThread extends Thread {

public Handler mHandler;

public void run() {

Looper.prepare();

mHandler = new Handler() {

public void handleMessage(Message msg) {

// process incoming messages here

}

};

Looper.loop();

}

}


Android中的Looper类,是用来封装消息循环和消息队列的一个类,用于在android线程中进行消息处理。handler其实可以看做是一个工具类,用来向消息队列中插入消息的。

(1) Looper类用来为一个线程开启一个消息循环。

默认情况下android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。)

Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。

(2) 通常是通过Handler对象来与Looper进行交互的。Handler可看做是Looper的一个接口,用来向指定的Looper发送消息及定义处理方法。

默认情况下Handler会与其被定义时所在线程的Looper绑定,比如,Handler在主线程中定义,那么它是与主线程的Looper绑定。

mainHandler = new Handler() 等价于new Handler(Looper.myLooper()).

Looper.myLooper():获取当前进程的looper对象,类似的 Looper.getMainLooper() 用于获取主线程的Looper对象。

(3) 在非主线程中直接new Handler() 会报如下的错误:

E/AndroidRuntime( 6173): Uncaught handler: thread Thread-8 exiting due to uncaught exception

E/AndroidRuntime( 6173): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

原因是非主线程中默认没有创建Looper对象,需要先调用Looper.prepare()启用Looper。

(4) Looper.loop(); 让Looper开始工作,从消息队列里取消息,处理消息。

注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。

(5) 基于以上知识,可实现主线程给子线程(非主线程)发送消息。

将代码中的mHandler声明成类成员,在主线程通过mHandler发送消息即可。



Handler

  Handler在android里负责发送和处理消息。它的主要用途有:

  1)按计划发送消息或执行某个Runnanble(使用POST方法);

  2)从其他线程中发送来的消息放入消息队列中,避免线程冲突(常见于更新UI线程)

   默认情况下,Handler接受的是当前线程下的消息循环实例(使用Handler(Looper looper)、Handler(Looper looper, Handler.Callback callback)可以指定线程),同时一个消息队列可以被当前线程中的多个对象进行分发、处理(在UI线程中,系统已经有一个Activity来处理了,你可以再起若干个Handler来处理)。在实例化Handler的时候,Looper可以是任意线程的,只要有Handler的指针,任何线程也都可以sendMessage。Handler对于Message的处理不是并发的。一个Looper 只有处理完一条Message才会读取下一条,所以消息的处理是阻塞形式的(handleMessage()方法里不应该有耗时操作,可以将耗时操作放在其他线程执行,操作完后发送Message(通过sendMessges方法),然后由handleMessage()更新UI)。

调度处理消息是通过调用post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long)和sendMessageDelayed(Message,long)等方法完成的。其中的post版本的方法可以让你将Runnable对象放进消息队列;sendMessage版本的方法可以让你将一个包含有bundle对象的消息对象放进消息队列,然后交由handleMessage(Message)方法处理。(这个需要你复写Handler的handleMessage方法)。



1.Handler使用post方法

使用post方法是将一个Runnable对象依附在主线程上面,并没有开启一个新的线程。注意:如果在Runnable对象中执行耗时的操作的话,还是会弹出ANR对话框。



2.Handler使用sendMessage方法

sendMessage有多种方式:

(一) Handler和sendMessage都在同一个线程里面

(二) Handler在主线程,sendMessage在子线程

(三) Handler在子线程,sendMessage在主线程

对于第一种情况,就是在创建Handler对象的时候重写handleMessage()方法,还是使用的是主线程,所以在处理消息中不能有耗时操作,否则会出现ANR对话框。

对于第二种情况,创建了一个新的线程,可以处理耗时操作,示例代码如下:

对于第三种情况,就要涉及到HandlerThread。由于在默认情况下,Handler接受的是当前线程下的消息循环实例,要使用子线程的消息队列,就得使用HandlerThread,它继承于Thread,与普通Thread的差别在于,它有一个Looper成员变量,这个Looper其实就是对消息队列以及队列处理逻辑的封装,简单说就是消息队列+消息循环。(当我们需要一个工作线程时,而不是把它当作一次性消耗品,用过即废弃的话,就可以使用HandlerThread)。



HandlerThread

  Android官方文档中Looper的介绍:

   Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.

HandlerThread源代码中的run方法代码如下:

public void run() {
mTid = Process.myTid();
Looper.prepare(); //使该线程拥有一个Looper对象
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop(); //让Looper开始工作,从消息队列里取消息,处理消息
mTid = -1;
}

继承了该类的Thread就拥有了Looper成员变量,可以处理Handler发送的消息。


 

  • 大小: 136.3 KB
  • 大小: 104.1 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics