您的位置:首页 > 产品设计 > UI/UE

Android应用开发——线程间通信之Handler+Looper+MessageQueue

2014-04-12 18:34 776 查看
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线程

参考:

/article/7601755.html 比较详细

/article/7601759.html

/article/1645877.html

http://www.eoeandroid.com/thread-40479-1-1.html

关于obtainMessage和sendMessage方法:

/article/6997010.html 比较详细

/article/9168267.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: