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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值