分享

Android异步消息处理

 dmw_zgl 2015-03-18

最近看了《Android内核剖析》这本书,将学习笔记整理如下

1. 异步消息线程

异步消息线程不同一般线程的是,它的线程run方法有一个无限循环,没循环一次,从其内部的消息队列中取出一个消息并调用回调函数进行处理。如果消息队列为空,线程暂停,直到消息队列中有新的消息。

 

一般而言有两种需求需要用到异步线程处理:

(1) 任务需要常驻

(2) 任务需要根据外部传递的消息做出不同的操作

 

2. Android异步线程的实现方法

 

在线程的内部有一个或多个Handler对象,外部程序通过该handler对象向线程发送异步消息,消息经由Handler传递到MessageQueue对象中。线程内部只能包含一个MessageQueue对象,线程主执行函数从MessageQueue中读取消息,并回调Handler对象中的回调函数handleMessage()。下面的代码是一个简单的实例。

 

 

Java代码  收藏代码
  1. class LooperThread extends Thread {  
  2.     public Handler mHandler;  
  3.       
  4.     public void run() {  
  5.         Looper.prepare();  
  6.           
  7.         mHandler = new Handler() {  
  8.             public void handleMessage(Message msg) {  
  9.                 // process incoming messages here  
  10.             }  
  11.         };  
  12.           
  13.         Looper.loop();  
  14.     }  
  15. }  

 

2.1 Looper

Looper的作用有两点,第一是调用静态函数prepare()为线程创建一个消息队列;第二是调用静态函数loop(),使调用该函数的线程进行无限循环,并从消息队列中读取消息。

(1)调用prepare()函数

 

Java代码  收藏代码
  1. public static final void prepare() {  
  2.     if (sThreadLocal.get() != null) {  
  3.         throw new RuntimeException("Only one Looper may be created per thread");  
  4.     }  
  5.     sThreadLocal.set(new Looper());  
  6. }  

   //Looper构造函数  

 

Java代码  收藏代码
  1. private Looper() {  
  2.       mQueue = new MessageQueue();  
  3.       mRun = true;  
  4.       mThread = Thread.currentThread();  
  5.   }  

 在代码中,变量sThreadLocal的类型是ThreadLocal,该类的作用是提供“线程局部存储”,从变量的作用域来理解下这个概念。

 

函数成员变量-------------------------------- 仅在函数内部有效
类成员变量 --------------------------------- 仅在对象内部有效
线程局部存储(TLS)变量-------------------- 在本线程内的任何对象内保持一致
类静态变量------------------------------------ 在本进程内的任何对象内保持一致
跨进程通信(IPC)变量----------------------- 一般使用Binder进行定义,在所有进程中保持一致

 

 

 

 

 

 

 

 

从上述的代码可以看到,一个线程只允许创建一个Looper对象,这是因为每个Looper对象都会创建一个MessageQueue对象,一个异步线程中只能有一个消息队列,所以也就只能有一个Looper对象

(2)调用loop()函数

 

Java代码  收藏代码
  1. public static final void loop() {  
  2.         Looper me = myLooper();  
  3.         MessageQueue queue = me.mQueue;  
  4.           
  5.         // Make sure the identity of this thread is that of the local process,  
  6.         // and keep track of what that identity token actually is.  
  7.         Binder.clearCallingIdentity();  
  8.         final long ident = Binder.clearCallingIdentity();  
  9.           
  10.         while (true) {  
  11.             // might block 如果队列为空,则当前线程就会被挂起,next()函数内部会暂停线程  
  12.             Message msg = queue.next();  
  13.               
  14.             if (msg != null) {  
  15.                 if (msg.target == null) {  
  16.                     // No target is a magic identifier for the quit message.  
  17.                     return;  
  18.                 }  
  19.                 if (me.mLogging!= null) me.mLogging.println(  
  20.                         ">>>>> Dispatching to " + msg.target + " "  
  21.                         + msg.callback + ": " + msg.what  
  22.                         );  
  23.                 //回调函数完成对消息的处理。msg.target的类型是Handler,msg最终交予handleMessage()处理  
  24.                 msg.target.dispatchMessage(msg);  
  25.                 if (me.mLogging!= null) me.mLogging.println(  
  26.                         "<<<<< Finished to    " + msg.target + " "  
  27.                         + msg.callback);  
  28.                   
  29.                 // Make sure that during the course of dispatching the  
  30.                 // identity of the thread wasn't corrupted.  
  31.                 final long newIdent = Binder.clearCallingIdentity();  
  32.                 if (ident != newIdent) {  
  33.                     Log.wtf("Looper", "Thread identity changed from 0x"  
  34.                             + Long.toHexString(ident) + " to 0x"  
  35.                             + Long.toHexString(newIdent) + " while dispatching to "  
  36.                             + msg.target.getClass().getName() + " "  
  37.                             + msg.callback + " what=" + msg.what);  
  38.                 }  
  39.                 //回收message对象占用的系统资源  
  40.                 msg.recycle();  
  41.             }  
  42.         }  
  43.     }  
   

 

2.2 MessageQueue

消息队列采用排队方式对消息进行处理,即先到的消息会先得到处理,但如果消息本身指定了被处理的时刻,则必须等到该时刻才能处理该消息。

 

2.3 Handler

尽管MessageQueue提供了直接读/写的函数接口,但对于应用程序员而言,一般不直接读/写消息队列。

程序员一般使用Handler类向消息队列发送消息,并重载Handler的handleMessage函数添加消息处理代码。

handler对象只能添加到有消息队列的线程中,否则会发生异常。因此,在构造Handler对象前,必须已经执行过Looper.prepare(),但prepare()不能被执行两次。

一个线程中可以包含多个Handler对象。在Looper.loop函数中,不同的Message对应不同的Handler对象,从而回调不同的handleMessage函数。

异步消息处理线程处理用于多线程的消息传递外,它还和跨进程调用(IPC)一起被使用,用于实现异步跨进程调用。

 

 

 

 

 

 


 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多