免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1248 | 回复: 2
打印 上一主题 下一主题

Android 消息机制 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-01-19 23:53 |只看该作者 |倒序浏览
  
Android 消息机制






在 Android 开发中,有时会需要进行一个耗时的操作,例如:联网从远程读取数据,或者读取本地较大的一个文件的时候,这样的操作会引起系统长时间的等待,这时用户不能操作其它动作。长时间的等待给人假死的感觉,用户体验不好。究其原因,因为这样的操作都是在一个线程中完成。解决的办法可以采用类似 AJAX 的异步操作,把这类耗时的操作都放在另一个线程中处理。

         线程内部或者线程之间需要进行信息的交互,那这个交互如何来实现的呢, Android 为我们提供了以下几个类进行线程间的信息交互。



1.Message

消息对象,顾名思义就是记录消息信息的载体类。这个类有几个比较重要的字段:

arg1 和 arg2 :我们可以使用两个字段用来存放我们需要传递的整型值,在 Service 中,我们可以用来存放 Service 的 ID 。
obj :该字段是 Object 类型,我们可以让该字段传递某个多项到消息的接受者中。
what :这个字段可以说是消息的标志,在消息处理中,我们可以根据这个字段的不同的值进行不同的处理,类似于我们在处理 Button 事件时,通过 switch(v.getId()) 判断是点击了哪个按钮。
在使用 Message 时,我们可以通过 new Message() 创建一个 Message 实例,但是 Android 更推荐我们通过 Message.obtain() 或者 Handler.obtainMessage() 获取 Message 对象。这并不一定是直接创建一个新的实例,而是先从消息池中看有没有可用的 Message 实例,存在则直接取出并返回这个实例。反之如果消息池中没有可用的 Message 实例,则根据给定的参数 new 一个新 Message 对象。 通过分析源码可得知, Android 系统默认情况下在消息池中实例化 10 个 Message 对象。



2.MessageQueue

消息队列,用来存放 Message 对象的数据结构,按照 “ 先进先出 ” 的原则存放消息。存放并非实际意义的保存,而是将 Message 对象以链表的方 式串联起来的。 MessageQueue 对象不需要我们自己创建,而是有 Looper 对象对其进行管理,一个线程最多只可以拥有一个 MessageQueue 。我们可以通过 Looper.myQueue() 获取当前线程中的 MessageQueue 。



3.Looper

MessageQueue 的管理者,在一个线程中,如果存在 Looper 对象,则必定存在 MessageQueue 对象,并且只存在一个 Looper 对象和一个 MessageQueue 对象。

在 Android 系统中,除了主线程有默认的 Looper 对象,其它线程默认是没有 Looper 对 象。如果想让我们新创建的线程拥有 Looper 对象时,我们首先需要调用 Looper.prepare() 来给线程创建一个消息循环,然后调用 Looper.loop() 来使消息循环起作用,从消息队列里取消息,处理消息。典型的用法如下:

Java代码
  1. class LooperThread extends Thread         
  2. {         
  3.     public Handler mHandler;         
  4.     public void run()         
  5.     {         
  6.         Looper.prepare();         
  7.         //其它需要处理的操作         
  8.         Looper.loop();         
  9.     }         
  10. }     

  11. class LooperThread extends Thread      
  12. {      
  13.     public Handler mHandler;      
  14.     public void run()      
  15.     {      
  16.         Looper.prepare();      
  17.         //其它需要处理的操作      
  18.         Looper.loop();      
  19.     }      
  20. }   
复制代码
4.Handler

消息的处理者。通过 Handler 对象我们可以封装 Message 对象,然后通过 sendMessage(msg) 把 Message 对象添加到 MessageQueue 中;当 MessageQueue 循环到该 Message 时,就会调用该 Message 对象对应的 handler 对象的 handleMessage() 方法对其进行处理。由于是在 handleMessage() 方法中处理消息,因此我们应该编写一个类继承自 Handler ,然后在 handleMessage() 处理我们需要的操作。

Java代码
  1. /**      
  2. *        
  3. * @author coolszy      
  4. * @blog http://blog.csdn.net/coolszy      
  5. *      
  6. */         
  7. public class MessageService extends Service         
  8.         
  9. {         
  10.     private static final String TAG = "MessageService";         
  11.     private static final int KUKA = 0;         
  12.     private Looper looper;         
  13.     private ServiceHandler handler;         
  14.     /**      
  15.      * 由于处理消息是在Handler的handleMessage()方法中,因此我们需要自己编写类      
  16.      * 继承自Handler类,然后在handleMessage()中编写我们所需要的功能代码      
  17.      * @author coolszy      
  18.      *      
  19.      */        
  20.     private final class ServiceHandler extends Handler         
  21.     {         
  22.         public ServiceHandler(Looper looper)         
  23.         {         
  24.             super(looper);         
  25.         }            
  26.         @Override        
  27.         public void handleMessage(Message msg)         
  28.         {         
  29.             // 根据what字段判断是哪个消息         
  30.             switch (msg.what)         
  31.             {         
  32.             case KUKA:         
  33.                 //获取msg的obj字段。我们可在此编写我们所需要的功能代码         
  34.                 Log.i(TAG, "The obj field of msg:" + msg.obj);         
  35.                 break;         
  36.             // other cases         
  37.             default:         
  38.                 break;         
  39.             }         
  40.             // 如果我们Service已完成任务,则停止Service         
  41.             stopSelf(msg.arg1);         
  42.         }         
  43.     }            
  44.     @Override        
  45.     public void onCreate()         
  46.     {         
  47.         Log.i(TAG, "MessageService-->onCreate()");         
  48.         // 默认情况下Service是运行在主线程中,而服务一般又十分耗费时间,如果         
  49.         // 放在主线程中,将会影响程序与用户的交互,因此把Service         
  50.         // 放在一个单独的线程中执行         
  51.         HandlerThread thread = new HandlerThread("MessageDemoThread", Process.THREAD_PRIORITY_BACKGROUND);         
  52.         thread.start();         
  53.         // 获取当前线程中的looper对象         
  54.         looper = thread.getLooper();         
  55.         //创建Handler对象,把looper传递过来使得handler、         
  56.         //looper和messageQueue三者建立联系         
  57.         handler = new ServiceHandler(looper);         
  58.     }         
  59.     @Override        
  60.     public int onStartCommand(Intent intent, int flags, int startId)         
  61.     {         
  62.         Log.i(TAG, "MessageService-->onStartCommand()");         
  63.         
  64.        //从消息池中获取一个Message实例         
  65.         Message msg = handler.obtainMessage();         
  66.        // arg1保存线程的ID,在handleMessage()方法中         
  67.         // 我们可以通过stopSelf(startId)方法,停止服务         
  68.         msg.arg1 = startId;         
  69.        // msg的标志         
  70.         msg.what = KUKA;         
  71.        // 在这里我创建一个date对象,赋值给obj字段         
  72.         // 在实际中我们可以通过obj传递我们需要处理的对象         
  73.         Date date = new Date();         
  74.        msg.obj = date;         
  75.        // 把msg添加到MessageQueue中         
  76.         handler.sendMessage(msg);         
  77.        return START_STICKY;         
  78.     }         
  79.     @Override        
  80.     public void onDestroy()         
  81.     {         
  82.         Log.i(TAG, "MessageService-->onDestroy()");         
  83.     }            
  84.     @Override        
  85.     public IBinder onBind(Intent intent)         
  86.     {         
  87.         return null;         
  88.     }         
  89. }      

  90.       /**     
  91.      *      
  92.      * @author coolszy     
  93.      * @blog http://blog.csdn.net/coolszy     
  94.      *     
  95.      */      
  96.     public class MessageService extends Service      
  97.          
  98.     {      
  99.         private static final String TAG = "MessageService";      
  100.         private static final int KUKA = 0;      
  101.         private Looper looper;      
  102.         private ServiceHandler handler;      
  103.         /**     
  104.          * 由于处理消息是在Handler的handleMessage()方法中,因此我们需要自己编写类     
  105.          * 继承自Handler类,然后在handleMessage()中编写我们所需要的功能代码     
  106.          * @author coolszy     
  107.          *     
  108.          */     
  109.         private final class ServiceHandler extends Handler      
  110.         {      
  111.             public ServiceHandler(Looper looper)      
  112.             {      
  113.                 super(looper);      
  114.             }         
  115.             @Override     
  116.             public void handleMessage(Message msg)      
  117.             {      
  118.                 // 根据what字段判断是哪个消息      
  119.                 switch (msg.what)      
  120.                 {      
  121.                 case KUKA:      
  122.                     //获取msg的obj字段。我们可在此编写我们所需要的功能代码      
  123.                     Log.i(TAG, "The obj field of msg:" + msg.obj);      
  124.                     break;      
  125.                 // other cases      
  126.                 default:      
  127.                     break;      
  128.                 }      
  129.                 // 如果我们Service已完成任务,则停止Service      
  130.                 stopSelf(msg.arg1);      
  131.             }      
  132.         }         
  133.         @Override     
  134.         public void onCreate()      
  135.         {      
  136.             Log.i(TAG, "MessageService-->onCreate()");      
  137.             // 默认情况下Service是运行在主线程中,而服务一般又十分耗费时间,如果      
  138.             // 放在主线程中,将会影响程序与用户的交互,因此把Service      
  139.             // 放在一个单独的线程中执行      
  140.             HandlerThread thread = new HandlerThread("MessageDemoThread", Process.THREAD_PRIORITY_BACKGROUND);      
  141.             thread.start();      
  142.             // 获取当前线程中的looper对象      
  143.             looper = thread.getLooper();      
  144.             //创建Handler对象,把looper传递过来使得handler、      
  145.             //looper和messageQueue三者建立联系      
  146.             handler = new ServiceHandler(looper);      
  147.         }      
  148.         @Override     
  149.         public int onStartCommand(Intent intent, int flags, int startId)      
  150.         {      
  151.             Log.i(TAG, "MessageService-->onStartCommand()");      
  152.          
  153.            //从消息池中获取一个Message实例      
  154.             Message msg = handler.obtainMessage();      
  155.            // arg1保存线程的ID,在handleMessage()方法中      
  156.             // 我们可以通过stopSelf(startId)方法,停止服务      
  157.             msg.arg1 = startId;      
  158.            // msg的标志      
  159.             msg.what = KUKA;      
  160.            // 在这里我创建一个date对象,赋值给obj字段      
  161.             // 在实际中我们可以通过obj传递我们需要处理的对象      
  162.             Date date = new Date();      
  163.            msg.obj = date;      
  164.            // 把msg添加到MessageQueue中      
  165.             handler.sendMessage(msg);      
  166.            return START_STICKY;      
  167.         }      
  168.         @Override     
  169.         public void onDestroy()      
  170.         {      
  171.             Log.i(TAG, "MessageService-->onDestroy()");      
  172.         }         
  173.         @Override     
  174.         public IBinder onBind(Intent intent)      
  175.         {      
  176.             return null;      
  177.         }      
  178.     }   
复制代码
注 :在测试代码中我们使用了 HandlerThread 类,该类是 Thread 的子类,该类运行时将会创建 looper 对象,使用该类省去了我们自己编写 Thread 子类并且创建 Looper 的麻烦。



下面我们分析下程序的运行过程:



1.onCreate()

首先启动服务时将会调用onCreate()方法,在该方法中我们new了一个HandlerThread对象,提供了线程的名字和优先级。

紧接着我们调用了start()方法,执行该方法将会调用HandlerThread对象的run()方法:

Java代码
  1. public void run() {         
  2.         mTid = Process.myTid();         
  3.         Looper.prepare();         
  4.         synchronized (this) {         
  5.             mLooper = Looper.myLooper();         
  6.             notifyAll();         
  7.         }         
  8.         Process.setThreadPriority(mPriority);         
  9.         onLooperPrepared();         
  10.         Looper.loop();         
  11.         mTid = -1;         
  12.     }   

  13.     public void run() {      
  14.             mTid = Process.myTid();      
  15.             Looper.prepare();      
  16.             synchronized (this) {      
  17.                 mLooper = Looper.myLooper();      
  18.                 notifyAll();      
  19.             }      
  20.             Process.setThreadPriority(mPriority);      
  21.             onLooperPrepared();      
  22.             Looper.loop();      
  23.             mTid = -1;      
  24.         }
复制代码
在run()方法中,系统给线程添加的Looper,同时调用了Looper的loop()方法:

Java代码
  1. public static final void loop() {           
  2.         Looper me = myLooper();         
  3.         MessageQueue queue = me.mQueue;         
  4.         while (true) {         
  5.             Message msg = queue.next(); // might block         
  6.             //if (!me.mRun) {         
  7.             //    break;         
  8.             //}         
  9.             if (msg != null) {         
  10.                 if (msg.target == null) {         
  11.                     // No target is a magic identifier for the quit message.         
  12.                     return;         
  13.                 }         
  14.                 if (me.mLogging!= null) me.mLogging.println(         
  15.                         ">>>>> Dispatching to " + msg.target + " "        
  16.                         + msg.callback + ": " + msg.what         
  17.                         );         
  18.                 msg.target.dispatchMessage(msg);         
  19.                 if (me.mLogging!= null) me.mLogging.println(         
  20.                         "<<<<< Finished to    " + msg.target + " "        
  21.                         + msg.callback);         
  22.                 msg.recycle();         
  23.             }         
  24.         }         
  25.     }     

  26.     public static final void loop() {        
  27.             Looper me = myLooper();      
  28.             MessageQueue queue = me.mQueue;      
  29.             while (true) {      
  30.                 Message msg = queue.next(); // might block      
  31.                 //if (!me.mRun) {      
  32.                 //    break;      
  33.                 //}      
  34.                 if (msg != null) {      
  35.                     if (msg.target == null) {      
  36.                         // No target is a magic identifier for the quit message.      
  37.                         return;      
  38.                     }      
  39.                     if (me.mLogging!= null) me.mLogging.println(      
  40.                             ">>>>> Dispatching to " + msg.target + " "     
  41.                             + msg.callback + ": " + msg.what      
  42.                             );      
  43.                     msg.target.dispatchMessage(msg);      
  44.                     if (me.mLogging!= null) me.mLogging.println(      
  45.                             "<<<<< Finished to    " + msg.target + " "     
  46.                             + msg.callback);      
  47.                     msg.recycle();      
  48.                 }      
  49.             }      
  50.         }  
复制代码

论坛徽章:
0
2 [报告]
发表于 2012-01-19 23:54 |只看该作者
谢谢分享

论坛徽章:
0
3 [报告]
发表于 2012-01-23 23:50 |只看该作者
学习学习。了解了啊。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP