Android 中的消息机制


我们先来看一些术语:

1.Parcel:其实就是一个容器,我们来看官方描述:Container for a message (data and object references) that can be sent through an IBinder。很简单,就是一个消息的集合,而这样的集合是可以通过IBinder接口发送的。

2.Message:Defines a message containing a description and arbitrary data object that can be sent to aHandler. :消息就是一种包含描述和任意数据而且能够发送给Handler的数据结构。

3.Handler:A Handler allows you to send and process Message and Runnable objects associated with a thread'sMessageQueue. Each Handler instance is associated with a single thread and that thread's message queue.:Handler 允许你发送以及处理与某个线程的消息队列关联的消息和Runnable对象。每个Handler实例是和单个线程以及它的消息队列是关联起来的。

4.Looper:Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, callprepare() in the thread that is to run the loop, and thenloop() to have it process messages until the loop is stopped.

Most interaction with a message loop is through the Handler class.:一个类,什么样的类呢?用于运行某个线程的消息循环的类。通常情况下,一个线程是不含一个与自身关联的消息loop的。如果new一个thread,需要在你的线程中调用prepare()函数来启动loop,然后loop()在终止之前会自己处理消息。对于一般的主线程来说,会自动创建一个mainloop与主线程绑定。可以使用getMainLooper()来获取主线程的loop函数。

5.MessageQueue:Low-level class holding the list of messages to be dispatched by aLooper. Messages are not added directly to a MessageQueue, but rather throughMessageQueue.IdleHandler objects associated with the Looper.You can retrieve the MessageQueue for the current thread withLooper.myQueue().:也是一个类,什么样的类呢?保存了N个用于被Looper分发的Message的类。因为我们的Message不是直接add到MessageQueue里面的,而是通过一个MessageQueue.IdleHandler的对象来和Looper关联起来的,我们可以通过Looper.myQueue()来获取到当前线程的消息队列。

 好了,上面的术语基本上都是Android消息机制相关的术语,也做了一些简单翻译,讨厌看的童鞋可以看看英文原始注释。俺们一起来理下思路:

     · N个消息放一起,堆在一个容器里面,该容器里面的东东而且能够通过IBinder形式发送,这就形成了Parcel。(Parcel的用法暂时不单独提了,后面相关技术文档会涉及到了就说,这个在Android Framework里面用的比较多。)

     ·通常我们的Message不是发一条就处理一条的,它首先是放在消息队列里面的进行逐条处理,怎么放到消息队列里面的呢?不是直接的add进去,而是和Looper关联的一个MessageQueue.IdleHandler对象来add进去的,这里就看到了,looper起到了Message和MessageQueue的一个桥梁作用(记住:消息队列中的消息也是由Looper给整出去的。),这个还不是最主要的。looper最主要的桥梁作用是Message和Handler,Looper它可以分发消息,分发的消息是给Hander进行发送和处理的。Hanlder通过looper从MessageQueue里面获取Message进行处理。它也可以get 消息,然后add到消息队列里面去。

6.AsyncTask :这是个异步任务机制,也是来捣鼓线程间通信的,该机制将相应操作在线程池中取出一个线程来执行,然后将结果传递给主线程,主线程拿到该结果后即可以进行更新界面等相应操作了。

AsyncTask的使用需要我们去创建一个继承自AsyncTask的类AsyncTask<Params, Progress, Result>,

参数说明如下:

  1. Params, the type of the parameters sent to the task upon execution.:发送给异步任务去执行的参数类型。
  2. Progress, the type of the progress units published during the background computation.:在后台执行程序的时候返回给调用线程进度的参数类型。
  3. Result, the type of the result of the background computation.:后台执行程序计算好的结果类型。
该类有如下几个子方法:

doInBackground(String... params) :后台执行程序,参数params是由调用线程传递过来。然后将返回的结果送给onPostExecute,   onPostExecute可以依据放回的结果来更新UI的操作。在子线程中操作。

onCancelled():可以在处理的过程中取消异步线程处理。如果执行已经结束的话该方式执行失败。在主线程中操作。

onPostExecute(String result):从doInBackground获取执行后的结果,然后可以对UI的主界面进行更新操作。该操作的执行是在主线程中。

onPreExecute() :执行子线程前进行的一系列的准备工作。该操作在主线程中操作。

onProgressUpdate(String... values):主线程中用于显示进度的函数,该函数由doInBackground()调用publishProgress()函数将结果发送过来。在主线程中操作。

以上几个函数都是回调函数,系统会自己调用,切忌不要手动去调用它。

通常情况下我们使用AsyncTask的情况会比较多,因为它比handle机制简单,而且使用起来也比较方便,在后面的例子中将会将两种情况一起使用。


实例:

介绍,该例子主要是利用Handle的消息机制实现一个音乐播放器;用AsyncTask形式实现点击按钮就更改UI界面的文字信息。两种方式都是多线程的通信方式。具体注释贴代码如下:

HandleMessageActivity.java

  1. import java.security.PublicKey;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.AsyncTask;  
  5. import android.os.Bundle;  
  6. import android.os.Handler;  
  7. import android.os.Message;  
  8. import android.view.View;  
  9. import android.widget.Button;  
  10. import android.widget.TextView;  
  11. import android.widget.Toast;  
  12. import android.os.Looper;  
  13. import android.content.Intent;  
  14. public class HandleMessageActivity extends Activity {  
  15.     /** Called when the activity is first created. */  
  16.     private Button mBtnPlayMusic = null;  
  17.     private Button mBtnStopMusic = null;  
  18.     private Button mBtnChangeWelInfo = null;  
  19.     private TextView mTextShowMusicName = null;  
  20.     private TextView mTextWelcomeInfo = null;  
  21.       
  22.     Looper loop = Looper.myLooper();//获取主线程的looper   
  23.     MyHandle myHandle = new MyHandle();//new一个Handle,来处理主线程的消息信息   
  24.       
  25.     private String mArgs = null;//这个用于AsyncTask中的参数传递。   
  26.       
  27.     @Override  
  28.     public void onCreate(Bundle savedInstanceState) {  
  29.         super.onCreate(savedInstanceState);  
  30.         setContentView(R.layout.main);  
  31.         mBtnPlayMusic = (Button)findViewById(R.id.play_music);  
  32.         mBtnStopMusic = (Button)findViewById(R.id.stop_music);  
  33.         mBtnChangeWelInfo = (Button)findViewById(R.id.changeText);  
  34.           
  35.         mTextShowMusicName = (TextView)findViewById(R.id.music_name);  
  36.         mTextWelcomeInfo = (TextView)findViewById(R.id.welcomeinfo);  
  37.           
  38.           
  39.         /** 
  40.          * 实现播放音乐的功能 
  41.          */  
  42.         mBtnPlayMusic.setOnClickListener(new Button.OnClickListener(){  
  43.   
  44.             @Override  
  45.             public void onClick(View v) {  
  46.                 // TODO Auto-generated method stub   
  47.                   
  48.                 new Thread(){  
  49.                     public void run(){  
  50.                         //实现细节   
  51.                         System.out.println(" star music:Current Thread ID is:"+Thread.currentThread().getId());  
  52.                         System.out.println("star music Current Thread Name is:"+Thread.currentThread().getName());  
  53.                         //获取包内的资源:取得music的全路径名称   
  54.                         String musicName = getResources().getString(R.raw.dongni);  
  55.                         System.out.println("the full of music name and path is:"+musicName);// res/raw/dongni.mp3   
  56.                         System.out.println("the full of resource name and path is:"+getResources().getResourceName(R.raw.dongni));//这里返回的包含了包得路径   
  57.                         //获取路径,不需要后缀名   
  58.                         int b = musicName.lastIndexOf("/");  
  59.                         int e = musicName.lastIndexOf(".");  
  60.                         String musicTrueName = musicName.substring(b+1, e);  
  61.                           
  62.                         /** 
  63.                          * 定义消息,并和Handle关联起来,这里注意的是,该消息只会和所定义的Handle关联起来, 
  64.                          * 而我们这里的Handle是在UI主线程里面创建的,所以此处的消息是会发送给UI的消息队列的。 
  65.                          */  
  66.                         Message message = myHandle.obtainMessage();  
  67.                         message.arg1 = 0;//用于区分在哪个线程里面发过来的Handle消息。   
  68.                         message.obj = musicTrueName;//所发送的对象   
  69.                         message.sendToTarget();//将消息发送给UI线程。   
  70.                                                   
  71.                         Intent intent = new Intent(HandleMessageActivity.this,MusicServer.class);  
  72.                         startService(intent);//启动service   
  73.                     }  
  74.                 }.start();  
  75.                   
  76.             }  
  77.         });  
  78.           
  79.         /** 
  80.          * 实现停止音乐播放的功能 
  81.          */  
  82.         mBtnStopMusic.setOnClickListener(new Button.OnClickListener(){  
  83.             public void onClick(View v){  
  84.                   
  85.                 new Thread() {  
  86.                       
  87.                     @Override  
  88.                     public void run() {  
  89.                         // TODO Auto-generated method stub   
  90.                         System.out.println("stop music Current Thread ID is:"+Thread.currentThread().getId());  
  91.                         System.out.println("stop music Current Thread Name is:"+Thread.currentThread().getName());  
  92.                         Message stopMsg = myHandle.obtainMessage();//获取消息对象,表示要发送给myHandle的消息   
  93.                         stopMsg.arg1 = 1;//给消息赋值   
  94.                         stopMsg.sendToTarget();//发给myHandle   
  95.                           
  96.                         Intent intent = new Intent(HandleMessageActivity.this,MusicServer.class);  
  97.                         stopService(intent);//停止service   
  98.                           
  99.                     }  
  100.                 }.start();  
  101.             }  
  102.         });  
  103.           
  104.         /** 
  105.          * 改变欢迎信息,这里使用AsynTask的方式来执行 
  106.          */  
  107.         mBtnChangeWelInfo.setOnClickListener(new Button.OnClickListener(){  
  108.               
  109.             public void onClick(View v){  
  110.                 System.out.println("in mBtnChangeWelInfo ,Current Thread ID is:"+Thread.currentThread().getId());  
  111.                 System.out.println("in mBtnChangeWelInfo ,Current Thread Name is:"+Thread.currentThread().getName());  
  112.                 mArgs = "100";  
  113.                 new AsynTask().execute(mArgs);  
  114.                   
  115.                   
  116.                 /* 
  117.                 new Runnable() { 
  118.                     @Override 
  119.                     public void run() { 
  120.                          
  121.                         System.out.println("Current Thread ID is:"+Thread.currentThread().getId()); 
  122.                         System.out.println("Current Thread Name is:"+Thread.currentThread().getName()); 
  123.                          
  124.                         Message changeTextMsg = myHandle.obtainMessage(); 
  125.                         changeTextMsg.arg1 = 20; 
  126.                         changeTextMsg.obj = "改变欢迎信息"; 
  127.                         changeTextMsg.sendToTarget(); 
  128.                     } 
  129.                 }.run(); 
  130.                 */  
  131.             }  
  132.         });  
  133.     }  
  134.     /** 
  135.      *  
  136.      * @author bluesky 
  137.      * 定义主线程的处理程序,这里我们复写handleMessage来处理发送给UI线程的消息。 
  138.      */  
  139.      class MyHandle extends Handler{  
  140.   
  141.          public MyHandle(){  
  142.          }  
  143.          public MyHandle(Looper loop){  
  144.              super(loop);  
  145.          }  
  146.         @Override  
  147.         public void dispatchMessage(Message msg) {  
  148.             // TODO Auto-generated method stub   
  149.             super.dispatchMessage(msg);  
  150.         }  
  151.   
  152.         @Override  
  153.         public void handleMessage(Message msg) {  
  154.             // TODO Auto-generated method stub   
  155.             super.handleMessage(msg);  
  156.             switch(msg.arg1){  
  157.             case 0:  
  158.             CharSequence getMusicName = (CharSequence)msg.obj;  
  159.             mTextShowMusicName.setText(getMusicName);  
  160.             break;  
  161.             case 1:  
  162.             CharSequence change = "no music played";  
  163.             mTextShowMusicName.setText(change);  
  164.             break;  
  165.            // case 20:   
  166.             //mTextWelcomeInfo.setText(msg.obj.toString());   
  167.             //break;   
  168.             default:  
  169.                 break;  
  170.             }  
  171.                   
  172.         }  
  173.   
  174.         @Override  
  175.         public boolean sendMessageAtTime(Message msg, long uptimeMillis) {  
  176.             // TODO Auto-generated method stub   
  177.             return super.sendMessageAtTime(msg, uptimeMillis);  
  178.         }  
  179.   
  180.         @Override  
  181.         public String toString() {  
  182.             // TODO Auto-generated method stub   
  183.             return super.toString();  
  184.         }  
  185.            
  186.           
  187.      }  
  188.      /** 
  189.       *  
  190.       * @author bluesky 
  191.       * 异步消息处理类,用于处理异步操作。 
  192.       */  
  193.   class AsynTask extends AsyncTask<String, String, String>{  
  194.   
  195.      /** 
  196.       * 后台进行一些处理操作,然后将返回的结果送给onPostExecute, 
  197.       * onPostExecute可以依据放回的结果来更新UI的操作。 
  198.       * 在线程池中操作 
  199.       */  
  200.     @Override  
  201.     protected String doInBackground(String... params) {  
  202.         // TODO Auto-generated method stub   
  203.         System.out.println("do InBackground,Current Thread ID is:"+Thread.currentThread().getId());  
  204.         System.out.println("do InBackground,Current Thread Name is:"+Thread.currentThread().getName());  
  205.         String getParam = null;  
  206.         getParam = params[0];  
  207.         String progress = "测试更新进度";  
  208.         publishProgress(progress);  
  209.         return getParam;  
  210.     }  
  211.     /** 
  212.      * 可以再处理的过程中取消异步线程处理。 
  213.      */  
  214.     @Override  
  215.     protected void onCancelled() {  
  216.         // TODO Auto-generated method stub   
  217.         System.out.println("do onCancelled,Current Thread ID is:"+Thread.currentThread().getId());  
  218.         System.out.println("do onCancelled,Current Thread Name is:"+Thread.currentThread().getName());  
  219.         super.onCancelled();  
  220.     }  
  221.   
  222.     /** 
  223.      * 从doInBackground获取执行后的结果,然后可以对UI的主界面进行更新操作。 
  224.      * 在主线程中操作 
  225.      */  
  226.     @Override  
  227.     protected void onPostExecute(String result) {  
  228.         // TODO Auto-generated method stub   
  229.         System.out.println("do onPostExecute,Current Thread ID is:"+Thread.currentThread().getId());  
  230.         System.out.println("do onPostExecute,Current Thread Name is:"+Thread.currentThread().getName());  
  231.         if(result == "100"){  
  232.             mTextWelcomeInfo.setText("AsynTask方式改变UI显示!");  
  233.         }  
  234.     }  
  235.   
  236.     /** 
  237.      * 在主线程中进行一系列的准备工作。 
  238.      *  
  239.      */  
  240.     @Override  
  241.     protected void onPreExecute() {  
  242.         // TODO Auto-generated method stub   
  243.         System.out.println("do onPreExecute,Current Thread ID is:"+Thread.currentThread().getId());  
  244.         System.out.println("do onPreExecute,Current Thread Name is:"+Thread.currentThread().getName());  
  245.         Toast.makeText(HandleMessageActivity.this"开始使用AsynTask来进行进程中通信", Toast.LENGTH_LONG).show();  
  246.         super.onPreExecute();  
  247.     }  
  248.   
  249.     /** 
  250.      * 主线程中用于显示进度的函数,该函数由doInBackground()调用publishProgress()函数将结果发送过来。 
  251.      */  
  252.     @Override  
  253.     protected void onProgressUpdate(String... values) {  
  254.         // TODO Auto-generated method stub   
  255.         String getProgress = values[0];  
  256.         System.out.println("do onProgressUpdate,Current Thread ID is:"+Thread.currentThread().getId());  
  257.         System.out.println("do onProgressUpdate,Current Thread Name is:"+Thread.currentThread().getName());       
  258.         System.out.println("do onProgressUpdate,Current value get from doInBackGround is:"+getProgress);  
  259.     }  
  260.         
  261.   }  
  262. }  
  • 1
  • 2
  • 下一页

相关内容