Android消息处理机制

Google参考了Windows的消息处理机制,在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进行处理。

 

图1 类关联关系图

 

运行机理:

      每个线程都可以并仅可以拥有一个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函数处理消息。
    

示例代码:

[java]  view plain  copy
 print ?
  1. public class MainThread extends Activity {  
  2.   
  3.     private static final String TAG = "MainThread";  
  4.     private Handler mMainHandler, mChildHandler;  
  5.     private TextView mInfoTextView;  
  6.     private Button mMsgButton;  
  7.   
  8.     @Override  
  9.     public void onCreate(Bundle savedInstanceState) {  
  10.         super.onCreate(savedInstanceState);  
  11.         setContentView(R.layout.main);  
  12.         mInfoTextView = (TextView) findViewById(R.id.info);  
  13.         mMsgButton = (Button) findViewById(R.id.msg);  
  14.         /** 
  15.          * 没有指定Looper,Handler将绑定创建它的线程的Looper,这里mMainHandler将绑定主线程的Looper 
  16.          *  
  17.          * 在主线程中不用显式调用Looper.prepare()创建Looper 
  18.          *  
  19.          */  
  20.         mMainHandler = new Handler() {  
  21.             @Override  
  22.             public void handleMessage(Message msg) {  
  23.                 // 接收子线程的消息  
  24.                 Log.i(TAG, "接收到从子线程发送过来的消息 - " + (String) msg.obj);  
  25.                 mInfoTextView.setText((String) msg.obj);  
  26.             }  
  27.         };  
  28.         // 创建并启动子线程  
  29.         new ChildThread().start();  
  30.         mMsgButton.setOnClickListener(new OnClickListener() {  
  31.             @Override  
  32.             public void onClick(View v) {  
  33.                 if (mChildHandler != null) {  
  34.                     // 构建消息对象  
  35.                     Message childMsg = mChildHandler.obtainMessage();  
  36.                     childMsg.obj = "我是主线程'"  
  37.                             + mMainHandler.getLooper().getThread().getName()  
  38.                             + "'";  
  39.                     // 发送消息给子线程  
  40.                     mChildHandler.sendMessage(childMsg);  
  41.                     Log.i(TAG, "发送给子线程的消息 - " + (String) childMsg.obj);  
  42.                 }  
  43.             }  
  44.         });  
  45.   
  46.     }  
  47.   
  48.     public void onDestroy() {  
  49.         super.onDestroy();  
  50.         Log.i(TAG, "Stop looping the child thread's message queue");  
  51.         // 关闭子线程的循环器  
  52.         mChildHandler.getLooper().quit();  
  53.     }  
  54.   
  55.     class ChildThread extends Thread {  
  56.   
  57.         private static final String CHILD_TAG = "ChildThread";  
  58.   
  59.         public void run() {  
  60.             this.setName("ChildThread");  
  61.             /** 
  62.              * 初始化消息队列,如果在子线程里创建Handler没有执行Looper.prepare()将报如下错误 
  63.              *  
  64.              * Can't create handler inside thread that has not called 
  65.              * Looper.prepare() 
  66.              */  
  67.             Looper.prepare();  
  68.             mChildHandler = new Handler() {  
  69.                 @Override  
  70.                 public void handleMessage(Message msg) {  
  71.                     Log.i(CHILD_TAG, "接收到从主线程发送过来的消息  - " + (String) msg.obj);  
  72.                     try {  
  73.                         // 在子线程中可以做一些耗时的工作  
  74.                         sleep(100);  
  75.                         // 构建消息对象  
  76.                         Message toMain = mMainHandler.obtainMessage();  
  77.                         toMain.obj = "我是子线程'"  
  78.                                 + this.getLooper().getThread().getName() + "'";  
  79.                         // 发送消息给主线程  
  80.                         mMainHandler.sendMessage(toMain);  
  81.                         Log.i(CHILD_TAG, "发送给总线程的消息 - " + (String) toMain.obj);  
  82.                     } catch (InterruptedException e) {  
  83.                         Log.e(TAG, e.getMessage());  
  84.                     }  
  85.                 }  
  86.             };  
  87.             // 启动子线程消息循环队列,开始处理消息  
  88.             Looper.loop();  
  89.         }  
  90.     }  
  91. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值