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有一个构造函数:
  public Message(){}; 
    通过该构造函数可以获得Massage对象,但是官方主要推荐通过Message.obtain()和Handler.obtainMessage()来获得Message对象,Message.obtain()有多个重载方法。使用Message的构造函数来创建Message对象需要重新分配一块新的内容,而通过Message.obtain()和Handler.obtainMessage()方法主要从全局消息槽中使用被回收的对象来创建Message,这样节省了一定的内存。
 
    例子:在子线程中通过Message构造函数创建Message对象,并通过Handler传递到主线程中。
 package zst.message01;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity implements OnClickListener {
private Button button01; public static final int ONE = 1; //在主线程中创建的Handler对象,通常定义成static
public static Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case ONE:
System.out.println("第一个Message-->" + "arg1=" + msg.arg1 + ",arg2=" + msg.arg2 + ",obj=" + msg.obj);
break;
default:
break;
}
} }; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button01 = (Button) findViewById(R.id.button01);
button01.setOnClickListener(this);
} @Override
public void onClick(View v) {
if(v.getId() == R.id.button01){
//启动一个子线程
new Thread(new Runnable() { @Override
public void run() {
//获得Message对象的第一种方法:使用构造函数创建Message,这种方法不推荐使用
Message message = new Message();
message.arg1 = 100;
message.arg2 = 200;
message.what = ONE; //用于标识Message
message.obj = "Message_01";
//发送Message到主线程中
handler.sendMessage(message); } }).start(); } }
}
     
  输出:Android多线程编程<二>Handler异步消息处理机制之Message
 
 
  2. 通过 public static Message obtain() 方法获得Message对象
                     //获得Message对象的第二种方法
Message message = Message.obtain();
message.arg1 = 100;
message.arg2 = 200;
message.what = TWO; //用于标识Message
message.obj = "Message_02";
handler.sendMessage(message);

   public static Message obtain()方法的源码如下:

 // sometimes we store linked lists of these things
/*package*/ Message next;
private static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}

   该方法将从全局消息槽中获得一个Message对象,从而避免再分配一块新的内存来创建Message对象。从上面可以看出,当全局消息槽中当前sPool不为null,则把sPool指向的Message对象赋给一个Message的临时引用,然后sPool再指向槽中的下一个Message,最后把临时引用m指向的Message对象返回给我们,这样全局消息槽中的Message可以得到重复使用,从而节省了一定的内存。如果sPool为null时,即消息槽为空,没有Message,这时才调用Message的构造函数来创建一个Message对象给我们。

 
    3. 通过 public static Message obtain(Handler h) 方法获得Message对象
              //获得Message对象的第三种方法:
Message message = Message.obtain(handler);
message.arg1 = 100;
message.arg2 = 200;
message.what = THREE; //用于标识Message
message.obj = "Message_03";
//发送Message
message.sendToTarget();

  public static Message obtain(Handler h)方法的源码如下:

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

  从上面源码中可以看出:该方法内部还是通过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)方法获得
               //获得Message对象的第四种方法:
Message message = Message.obtain(handler, FOUR);
message.arg1 = 100;
message.arg2 = 200;
message.obj = "Message_04";
message.sendToTarget();

  public static Message obtain(Handler h, int what)方法的源码如下:

 /**
* Same as {@link #obtain()}, but sets the values for both <em>target</em> and
* <em>what</em> members on the Message.
* @param h Value to assign to the <em>target</em> member.
* @param what Value to assign to the <em>what</em> member.
* @return A Message object from the global pool.
*/
public static Message obtain(Handler h, int what) {
Message m = obtain();
m.target = h;
m.what = what;
return m;
}
     从上面的源码可以看出:该方法的源码和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)方法源码:
 /**
* Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, and <em>obj</em>
* members.
* @param h The <em>target</em> value to set.
* @param what The <em>what</em> value to set.
* @param obj The <em>object</em> method to set.
* @return A Message object from the global pool.
*/
public static Message obtain(Handler h, int what, Object obj) {
Message m = obtain();
m.target = h;
m.what = what;
m.obj = obj;
return m;
}

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

 /**
* Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
* <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
*
* @param h The <em>target</em> value to set.
* @param what The <em>what</em> value to set.
* @param arg1 The <em>arg1</em> value to set.
* @param arg2 The <em>arg2</em> value to set.
* @param obj The <em>obj</em> value to set.
* @return A Message object from the global pool.
*/
public static Message obtain(Handler h, int what,
int arg1, int arg2, Object obj) {
Message m = obtain();
m.target = h;
m.what = what;
m.arg1 = arg1;
m.arg2 = arg2;
m.obj = obj;
return m;
}

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

  /**
* Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
* <em>arg1</em>, and <em>arg2</em> members.
*
* @param h The <em>target</em> value to set.
* @param what The <em>what</em> value to set.
* @param arg1 The <em>arg1</em> value to set.
* @param arg2 The <em>arg2</em> value to set.
* @return A Message object from the global pool.
*/
public static Message obtain(Handler h, int what, int arg1, int arg2) {
Message m = obtain();
m.target = h;
m.what = what;
m.arg1 = arg1;
m.arg2 = arg2;
return m;
}
   
 三. Message还可以携带Bundle对象
    添加Bundle对象
                  Message message = Message.obtain(handler, EIGHT, 100, 200);
message.obj = "Message_08";
Bundle b = new Bundle();
b.putString("name", "张三");
message.setData(b);
message.sendToTarget();
    取出Bundle对象
  String name = msg.getData().getString("name") 
 
 
例子源码:D:\Android\workspace\ThreadAndAsync\Message01
 
 
 
上一篇:Azure CosmosDB (9) Unique Key Constraints


下一篇:python3【基础】-赋值与深浅拷贝