1、需求
每个Android应用程序都运行在一个dalvik虚拟机进程中,进程开始的时候会启动一个主线程(MainThread),主线程负责处理和ui相关的事件,因此主线程通常又叫UI线程。而由于Android采用UI单线程模型(线程不安全),所以只能在主线程中对UI元素进行操作。如果在非UI线程直接对UI进行了操作,则会报错。
为了解决以上问题,Android中提供了Handler+Looper+MessageQueue的消息循环机制。可以利用这个机制来实现线程间的通信。那么,我们就可以在非UI线程发送消息到UI线程,最终让Ui线程来进行ui的操作。对于运算量较大的操作和IO操作,我们需要新开线程来处理这些繁重的工作,以免阻塞ui线程。
2、Handler+Looper+MessageQueue原理
Android使用消息机制实现线程间的通信,线程通过Looper建立自己的消息循环,MessageQueue是FIFO的消息队列,Looper负责从MessageQueue中取出消息,并且分发到消息指定目标Handler对象。Handler对象绑定到线程的局部变量Looper,封装了发送消息和处理消息的接口。
消息循环的核心是Looper,Looper持有消息队列MessageQueue对象,一个线程可以把Looper设为该线程的局部变量,这就相当于这个线程建立了一个对应的消息队列。Handler的作用就是封装发送消息和处理消息的过程,让其他线程只需要操作Handler就可以发消息给创建Handler的线程。
为一个线程建立消息循环有四个步骤:
1、 初始化Looper
2、 绑定handler到线程实例的Looper对象
3、 定义处理消息的方法
4、 启动消息循环
3、实例
3.1 UI线程发送消息至Work Thread
3.1.1 初始化Looper
一个线程在调用Looper的静态方法prepare()时,这个线程会新建一个Looper对象,并放入到线程的局部变量中,而这个变量是不和其他线程共享的。
/* 定义工作线程类 */
class WorkThread extends Thread{
/* 重写run方法 */
public void run(){
/* Looper初始化 */
Looper.prepare();
}
}
prepare方法源代码如下:
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
Looper中定义了成员变量,即该线程对象拥有了该Looper对象,相当于工作线程拥有了自己的消息队列。
final MessageQueue mQueue;
3.1.2 绑定handler到线程实例的Looper对象
该变量必须定义在UI线程和Work线程都能访问的地方:
private Handler myHandler;
但是,创建Handler对象时,必须在Work线程中,这样才能将Handler绑定到Work线程实例的Looper对象:
/* 定义工作线程类 */
class WorkThread extends Thread{
/* 重写run方法 */
public void run(){
/* Looper初始化 */
Looper.prepare();
/* 创建myHandler对象 */
myHandler = new Handler(){
};
}
}
Handler类的构造函数如下:
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper(); /* 绑定Looper对象 */
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; /* 绑定消息队列 */
mCallback = callback;
mAsynchronous = async;
}
Handler通过mLooper = Looper.myLooper();绑定到线程的局部变量Looper上去,同时Handler通过mQueue =mLooper.mQueue;获得线程的消息队列。此时,Handler就绑定到创建此Handler对象的线程的消息队列上了。
3.1.3 定义处理消息的方法
/* 创建myHandler对象 */
myHandler = new Handler(){
public void handleMessage(Message msg) {
}
};
3.1.4 启动消息循环
Looper.loop();
3.2 Work Thread发送消息至UI线程
参考:
http://blog.youkuaiyun.com/mylzc/article/details/6736988 比较详细
http://blog.youkuaiyun.com/mylzc/article/details/6771331
http://blog.youkuaiyun.com/qxs965266509/article/details/9059735
http://www.eoeandroid.com/thread-40479-1-1.html
关于obtainMessage和sendMessage方法:
http://www.cnblogs.com/android007/archive/2012/05/10/2494766.html 比较详细
http://blog.youkuaiyun.com/imdxt1986/article/details/7041570