Android多線程編程<二>Handler異步消息處理機制之Message

 
Message(消息):
 
    一. Message的字段:
    在Android中,Message做爲線程之間(主要是子線程和UI主線程之間)數據交換的載體,經過Handler去傳遞。它包含幾個經常使用的字段:
    1.arg1和arg2兩個int類型的字段:主要在線程之間須要傳遞簡單的int類型的數據時使用。
    2.what字段:int類型,主要用於標識一個Message。當在子線程中定義一個Message時,一般指定what的值爲一個int常量,該Message傳遞到主線程時,咱們經過what的值識別該Message。
    3.obj字段:是一個任意類型的對象,線程之間要交換的數據,主要是經過該字段來存儲。
 
    二. 得到Massage對象
 
    1. 經過構造函數得到Message對象,Message有一個構造函數:
  1 public Message(){}; 
    經過該構造函數能夠得到Massage對象,可是官方主要推薦經過Message.obtain()和Handler.obtainMessage()來得到Message對象, Message.obtain()有多個重載方法。使用Message的構造函數來建立Message對象須要從新分配一塊新的內容,而經過 Message.obtain()和Handler.obtainMessage()方法主要從全局消息槽中使用被回收的對象來建立Message,這樣節省了必定的內存。
 
    例子:在子線程中經過Message構造函數建立Message對象,並經過Handler傳遞到主線程中。
 1 package zst.message01;
 2 import android.os.Bundle;
 3 import android.os.Handler;
 4 import android.os.Message;
 5 import android.app.Activity;
 6 import android.view.Menu;
 7 import android.view.View;
 8 import android.view.View.OnClickListener;
 9 import android.widget.Button;
10 public class MainActivity extends Activity implements OnClickListener {
11     private Button button01;
12     
13     public static final int ONE = 1;
14     
15     
16     //在主線程中建立的Handler對象,一般定義成static
17     public static  Handler handler = new Handler(){
18         @Override
19         public void handleMessage(Message msg) {
20             switch (msg.what) {
21             case ONE:
22                 System.out.println("第一個Message-->" + "arg1=" + msg.arg1 + ",arg2=" + msg.arg2 + ",obj=" + msg.obj);
23                 break;
24             default:
25                 break;
26             }
27         }
28         
29             
30     };
31     
32     
33     @Override
34     protected void onCreate(Bundle savedInstanceState) {
35         super.onCreate(savedInstanceState);
36         setContentView(R.layout.activity_main);
37         button01 = (Button) findViewById(R.id.button01);
38         button01.setOnClickListener(this);
39     }
40     
41     @Override
42     public void onClick(View v) {
43         if(v.getId() == R.id.button01){
44             //啓動一個子線程
45             new Thread(new Runnable() {
46                 
47                 @Override
48                 public void run() {
49                     //得到Message對象的第一種方法:使用構造函數建立Message,這種方法不推薦使用
50                     Message message = new Message();
51                     message.arg1 = 100;
52                     message.arg2 = 200;
53                     message.what = ONE;   //用於標識Message
54                     message.obj = "Message_01";
55                     //發送Message到主線程中
56                     handler.sendMessage(message);
57                     
58                 }
59                 
60             }).start();
61             
62         }
63         
64         
65     }
66 }
     
  輸出:
 
 
  2. 經過 public static Message obtain() 方法得到Message對象
1                     //得到Message對象的第二種方法
2                     Message message = Message.obtain();
3                     message.arg1 = 100;
4                     message.arg2 = 200;
5                     message.what = TWO;   //用於標識Message
6                     message.obj = "Message_02";
7                     handler.sendMessage(message);

   public static Message obtain()方法的源碼以下:android

 

 1 // sometimes we store linked lists of these things
 2     /*package*/ Message next;
 3     private static final Object sPoolSync = new Object();
 4     private static Message sPool;
 5     private static int sPoolSize = 0;
 6     private static final int MAX_POOL_SIZE = 50;
 7     /**
 8      * Return a new Message instance from the global pool. Allows us to
 9      * avoid allocating new objects in many cases.
10      */
11     public static Message obtain() {
12         synchronized (sPoolSync) {
13             if (sPool != null) {
14                 Message m = sPool;
15                 sPool = m.next;
16                 m.next = null;
17                 sPoolSize--;
18                 return m;
19             }
20         }
21         return new Message();
22     }

 

   該方法將從全局消息槽中得到一個Message對象,從而避免再分配一塊新的內存來建立Message對象。從上面能夠看出,當全局消息槽中當前sPool不爲null,則把sPool指向的Message對象賦給一個Message的臨時引用,而後sPool再指向槽中的下一個Message,最後把臨時引用m指向的Message對象返回給咱們,這樣全局消息槽中的Message能夠獲得重複使用,從而節省了必定的內存。若是sPool爲null時,即消息槽爲空,沒有Message,這時才調用Message的構造函數來建立一個Message對象給咱們。app

 
    3. 經過 public static Message obtain(Handler h) 方法得到Message對象
1              //得到Message對象的第三種方法:
2                     Message message = Message.obtain(handler);
3                     message.arg1 = 100;
4                     message.arg2 = 200;
5                     message.what = THREE;   //用於標識Message
6                     message.obj = "Message_03";    
7                     //發送Message
8                     message.sendToTarget();

  public static Message obtain(Handler h)方法的源碼以下:ide

 

 1  /**
 2      * Same as {@link #obtain()}, but sets the value for the <em>target</em> member on the Message returned.
 3      * @param h  Handler to assign to the returned Message object's <em>target</em> member.
 4      * @return A Message object from the global pool.
 5      */
 6     public static Message obtain(Handler h) {
 7         Message m = obtain();
 8         m.target = h;
 9         return m;
10     }

 

  從上面源碼中能夠看出:該方法內部仍是經過public static Message obtain()方法從全局消息槽中返回一個Message對象給咱們,而後把傳入的Handler對象參數當成發送和接收該Message對象的目標Handler對象。因爲該方法內部已經指定了處理Message對象的目標Handler對象,因此在發送Message消息時,不會再調用Handler對象的sendMessage(message)方法,而是直接使用Message對象的sendToTarget()方法發送。函數

 
    4. 經過public static Message obtain(Handler h, int what)方法得到
1               //得到Message對象的第四種方法:
2                     Message message = Message.obtain(handler, FOUR);
3                     message.arg1 = 100;
4                     message.arg2 = 200;
5                     message.obj = "Message_04";    
6                     message.sendToTarget();

  public static Message obtain(Handler h, int what)方法的源碼以下:this

 

 1 /**
 2      * Same as {@link #obtain()}, but sets the values for both <em>target</em> and
 3      * <em>what</em> members on the Message.
 4      * @param h  Value to assign to the <em>target</em> member.
 5      * @param what  Value to assign to the <em>what</em> member.
 6      * @return A Message object from the global pool.
 7      */
 8     public static Message obtain(Handler h, int what) {
 9         Message m = obtain();
10         m.target = h;
11         m.what = what;
12         return m;
13     }

 

     從上面的源碼能夠看出:該方法的源碼和 public static Message obtain(Handler h)方法的源碼相似,都是先 經過 public static Message obtain()方法從全局消息槽中得到Message對象,再指定目標Handler對象,同時也指定Message的what字段值。
   
  還有其餘三個 obtain()的重載方法也是這樣,不一樣點是在建立Message對象時,同時指定Message的不一樣字段值。以下:
      public static Message obtain(Handler h, int what, Object obj)方法源碼:
 1 /**
 2      * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, and <em>obj</em>
 3      * members.
 4      * @param h  The <em>target</em> value to set.
 5      * @param what  The <em>what</em> value to set.
 6      * @param obj  The <em>object</em> method to set.
 7      * @return  A Message object from the global pool.
 8      */
 9     public static Message obtain(Handler h, int what, Object obj) {
10         Message m = obtain();
11         m.target = h;
12         m.what = what;
13         m.obj = obj;
14         return m;
15     }

  public static Message obtain(Handler h, int what, int arg1, int arg2, Object obj)方法源碼:spa

 1 /**
 2      * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, 
 3      * <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
 4      * 
 5      * @param h  The <em>target</em> value to set.
 6      * @param what  The <em>what</em> value to set.
 7      * @param arg1  The <em>arg1</em> value to set.
 8      * @param arg2  The <em>arg2</em> value to set.
 9      * @param obj  The <em>obj</em> value to set.
10      * @return  A Message object from the global pool.
11      */
12     public static Message obtain(Handler h, int what, 
13             int arg1, int arg2, Object obj) {
14         Message m = obtain();
15         m.target = h;
16         m.what = what;
17         m.arg1 = arg1;
18         m.arg2 = arg2;
19         m.obj = obj;
20         return m;
21     }

  public static Message obtain(Handler h, int what, int arg1, int arg2)方法源碼:線程

 1  /**
 2      * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, 
 3      * <em>arg1</em>, and <em>arg2</em> members.
 4      * 
 5      * @param h  The <em>target</em> value to set.
 6      * @param what  The <em>what</em> value to set.
 7      * @param arg1  The <em>arg1</em> value to set.
 8      * @param arg2  The <em>arg2</em> value to set.
 9      * @return  A Message object from the global pool.
10      */
11     public static Message obtain(Handler h, int what, int arg1, int arg2) {
12         Message m = obtain();
13         m.target = h;
14         m.what = what;
15         m.arg1 = arg1;
16         m.arg2 = arg2;
17         return m;
18     }
   
 三. Message還能夠攜帶Bundle對象
    添加Bundle對象
1                  Message message = Message.obtain(handler, EIGHT, 100, 200);
2                     message.obj = "Message_08";
3                     Bundle b = new Bundle();
4                     b.putString("name", "張三");
5                     message.setData(b);
6                     message.sendToTarget();
    取出Bundle對象
  1 String name = msg.getData().getString("name") 
 
 
例子源碼:D:\Android\workspace\ThreadAndAsync\Message01
 
 
 
相關文章
相關標籤/搜索