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.
1 class LooperThread extends Thread { 2 3 public Handler mHandler; 4 5 public void run() { 6 7 Looper.prepare(); 8 9 mHandler = new Handler() { 10 11 public void handleMessage(Message msg) { 12 13 // process incoming messages here 14 15 } 16 17 }; 18 19 Looper.loop(); 20 21 } 22 23 }
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方法代码如下:
mTid = Process.myTid();
Looper.prepare(); //使该线程拥有一个Looper对象
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop(); //让Looper开始工作,从消息队列里取消息,处理消息
mTid = -1;
}
继承了该类的Thread就拥有了Looper成员变量,可以处理Handler发送的消息。
程序运行结果如下: