Android的消息处理机制

学习Android的消息处理机制,有几个概念(类)必须了解:

1.Message 消息,理解为线程间通讯的数据单元。例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程。 2.Message Queue 消息队列,用来存放通过Handler发布的消息,按照先进先出执行。 3.Handler Handler是Message的主要处理者,负责将Message添加到消息队列以及对消息队列中的Message进行处理。 4.Looper 循环器,扮演Message Queue和Handler之间桥梁的角色,循环取出Message Queue里面的Message,并交付给相应的Handler进行处理。 5.线程 UI thread 通常就是main thread,而Android启动程序时会替它建立一个Message Queue。 每一个线程里可含有一个Looper对象以及一个MessageQueue数据结构。在你的应用程序里,可以定义Handler的子类别来接收Looper所送出的消息。

运行机理:

每个线程都可以并仅可以拥有一个Looper实例,消息队列MessageQueue在Looper的构造函数中被创建并且作为成员变量被保存,也就是说MessageQueue相对于线程也是唯一的。Android应用在启动的时候会默认会为主线程创建一个Looper实例,并借助相关的Handler和Looper里面的MessageQueue完成对Activities、Services、Broadcase Receivers等的管理。而在子线程中,Looper需要通过显式调用Looper. Prepare()方法进行创建。Prepare方法通过ThreadLocal来保证Looper在线程内的唯一性,如果Looper在线程内已经被创建并且尝试再度创建”Only one Looper may be created per thread”异常将被抛出。

Handler在创建的时候可以指定Looper,这样通过Handler的sendMessage()方法发送出去的消息就会添加到指定Looper里面的MessageQueue里面去。在不指定Looper的情况下,Handler绑定的是创建它的线程的Looper。如果这个线程的Looper不存在,程序将抛出”Can’t create handler inside thread that has not called Looper.prepare()”。

整个消息处理的大概流程是:1. 包装Message对象(指定Handler、回调函数和携带数据等);2. 通过Handler的sendMessage()等类似方法将Message发送出去;3. 在Handler的处理方法里面将Message添加到Handler绑定的Looper的MessageQueue;4. Looper的loop()方法通过循环不断从MessageQueue里面提取Message进行处理,并移除处理完毕的Message;5. 通过调用Message绑定的Handler对象的dispatchMessage()方法完成对消息的处理。

在dispatchMessage()方法里,如何处理Message则由用户指定,三个判断,优先级从高到低:1. Message里面的Callback,一个实现了Runnable接口的对象,其中run函数做处理工作;2. Handler里面mCallback指向的一个实现了Callback接口的对象,由其handleMessage进行处理;3. 处理消息Handler对象对应的类继承并实现了其中handleMessage函数,通过这个实现的handleMessage函数处理消息。

1.上面说的handler是一个关键的组件,它关联一个Looper,关联一个msg,还有它自己的的处理方法。把处理消息的三个要素全部结合在一起了,运行的线程、处理的方法、处理的数据,三个要素可以灵活配置。 如果handler与Looper没有关系,那么这个handler可以理解成一个函数对象,带着操作,带着数据,就是等待线程func()执行它。这里把“函数对象”(或者理解为命令模式中的一个command)如何放入指定的Looper给封装起来,并且把消息队列也给封装了起来,使用的时候就很方便了。 一段使用的例子如下:

Looper looper = Looper.myLooper();//取得当前线程里的looper
MyHandler mHandler =new MyHandler(looper);//构造一个handler使之可与looper通信
//buton等组件可以由mHandler将消息传给looper后,再放入messageQueue中,同时mHandler也可以接受来自looper消息
mHandler.removeMessages(0);
String msgStr ="主线程不同组件通信:消息来自button";
Message m = mHandler.obtainMessage(1, 1, 1, msgStr);//构造要传递的消息
mHandler.sendMessage(m);//发送消息:系统会自动调用handleMessage方法来处理消息

privateclass MyHandlerextends Handler{             
	 public MyHandler(Looper looper){
			super(looper);
	  }
	 @Override
	 publicvoid handleMessage(Message msg) {//处理消息
			text.setText(msg.obj.toString());
	  }            
}

上面的更新操作较简单。如果界面更新线程是单线程(也应该是单线程)那么,在更新界面操作中不需要加锁。而且在一般的线程通信时候,如果线程之间都是handler通过发送msg的方式传递消息,那么大多数操作也是不用加锁的。需要加锁的地方很多都已经封装起来了,例如mHandler.sendMessage时候向消息队列传递消息和从消息队列中获取消息的过程。

2.Android框架还规定了更新ui必须在ui线程中,这种做法不仅安全,而且高效。一般界面框架都有专门单独的更新ui的线程,但要特别注意,更新操作一般是阻塞的不要处理耗时过长的操作。

http://www.cnblogs.com/qingblog/archive/2012/06/27/2566021.html

Table of Contents