通过Thread + Handler + Message的方式在子线程中发送信息,然后在控制台中输出。代码与上一讲中的代码架构类似,我们主要是看一下子线程中run()的处理和Handler的处理。
private Handler handler = new Handler(){
@Override
public void handleMessage(android.os.Message msg) {
int arg1 = msg.arg1;
int arg2 = msg.arg2;
int what = msg.what;
Object result = msg.obj;
System.out.println("--> arg1: " + arg1);
System.out.println("--> arg2: " + arg2);
System.out.println("--> what: " + what);
System.out.println("--> result: " + result);
}
};
1) 通过 Message.obtain()方式获取Message对象
public class MyThread implements Runnable{
@Override
public void run() {
// 使用第一种构造方法
Message message = Message.obtain();
message.what = 1;
message.arg1 = 1;
message.arg2 = 3;
message.obj = "AHuier";
handler.sendMessage(message);
}
} 程序执行输出如下图所示:
[分析源码]: 这种方式博文上述中已经分析过了,主要工作是在Message对象池中获取对象。
2) 通过 Message.obtain(Handler h)的方式获取Message对象
/*
* 第二种获取Message对象的方法
* public static Message obtain (Handler h)
* 传递一个关联到消息Handler.
*/
Message message = Message.obtain(handler);
message.what = 1;
message.arg1 = 1;
message.arg2 = 3;
message.obj = "AHuier";
message.sendToTarget(); // 完成发送消息的动作
[分析源码]:
/**
* Same as {@link #obtain()}, but sets the value for the target member on the Message returned.
* @param h Handler to assign to the returned Message object's target member.
* @return A Message object from the global pool.
*/
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
} 先调用obtain()的方式来获取Message对象,然后把Handler的对象给了Message,我们查看一下sendToTarget()的操作: ...
/*package*/ Handler target;
...
/**
* Sends this Message to the Handler specified by {@link #getTarget}.
* Throws a null pointer exception if this field has not been set.
*/
public void sendToTarget() {
target.sendMessage(this);
}它是完成发送消息的动作,所以这种方式不需要在通过sendMessage的方式来处理了。只需要调用messge.sendToTarget();的方式就可以了。
3) 通过 Message.obtain(Handler h)的方式获取Message对象
/*
* 第三种获取Message对象的方法
* public static Message obtain (Handler h, int what)
* 关联一个Handler和传递一个what的属性值
*/
Message message = Message.obtain(handler, 1);
message.arg1 = 1;
message.arg2 = 3;
message.obj = "AHuier";
message.sendToTarget();[分析源码]:
/**
* Same as {@link #obtain()}, but sets the values for both target and
* what members on the Message.
* @param h Value to assign to the target member.
* @param what Value to assign to the what 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;
}
从源码我们可以看出这种方式更为简便,它也是内部将handle和what都赋值给Message对象,从而简化我们的代码。
4) 通过 Message.obtain(Handler h, int what, int arg1, int arg2, Object obj)的方式获取Message对象
/*
* public static Message obtain (Handler h, int what, int arg1, int arg2, Object obj)
* 关联Handler和传递Message的几种常用属性值
*/
Message message = Message.obtain(handler, 1, 1, 3, "AHuier");
message.sendToTarget();[分析源码]:
/**
* Same as {@link #obtain()}, but sets the values of the target, what,
* arg1, arg2, and obj members.
*
* @param h The target value to set.
* @param what The what value to set.
* @param arg1 The arg1 value to set.
* @param arg2 The arg2 value to set.
* @param obj The obj 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;
}同理,从源码中我们可以看出它也是在obtain()方法内部将传递过来的参数赋值给Message对象了。
5) 通过上述几个例子我们可以知道Message中的obtain()的几种重载方法在底层的实现都是大同小异的,他们都是底层都是首先调用obtain()方法来从消息池中获得一个消息的对象的。然后在通过参数传递来封装指定的Handler和需要携带的数据。如果使用这些重载的方法建议完成数据封装之后调用sendToTarget()方法。这就是几种obtain()重载方法的不同。
6) 这里我们需要特别注意Message中的这个重载方法:Message obtain (Message orig) 它是将原有的消息体作为一个新的消息参数来发送的,我们看一下它的源代码。
/**
* Same as {@link #obtain()}, but copies the values of an existing
* message (including its target) into the new one.
* @param orig Original message to copy.
* @return A Message object from the global pool.
*/
public static Message obtain(Message orig) {
Message m = obtain();
m.what = orig.what;
m.arg1 = orig.arg1;
m.arg2 = orig.arg2;
m.obj = orig.obj;
m.replyTo = orig.replyTo;
if (orig.data != null) {
m.data = new Bundle(orig.data);
}
m.target = orig.target;
m.callback = orig.callback;
return m;
}通过源码知道,同样它首先先从Message对象池中获取Message对象,然后将原有Message中的各种属性值赋予新的信息中的各种属性值,最后返回新的消息对象,再发送出去。1) 在前面的Message的Demo中,我们采用的都是传递Message自带的属性来传递一些轻量级的int类型和Object类型数据,那么如果是复杂一点的数据类型,Message也是可以传递的,传递的方式是就是采用Bundle的方式。
2) 查看Message中的api文档,我们就是采用setData(Bundle data)方法来绑定一个Bundle类型对象,而你可以往Bundle里面填充各种类型。
3) 程序Demo如下
i. 往Bundle中填入数据,同时发送消息
/*
* public static Message obtain (Handler h, int what, int arg1, int arg2, Object obj)
* 关联Handler和传递Message的几种常用属性值
*/
Message message = Message.obtain(handler, 1, 1, 3, "AHuier");
Bundle data = new Bundle();
data.putStringArray("str", new String[]{"AHui", "AHui1", "AHui2"});
message.setData(data);
message.sendToTarget();ii. 处理消息,同时从Bundle中取出数据,打印到控制台,输出键"str"的字符串数组长度为3 private Handler handler = new Handler(){
@Override
public void handleMessage(android.os.Message msg) {
int arg1 = msg.arg1;
int arg2 = msg.arg2;
int what = msg.what;
Object result = msg.obj;
System.out.println("--> arg1: " + arg1);
System.out.println("--> arg2: " + arg2);
System.out.println("--> what: " + what);
System.out.println("--> result: " + result);
System.out.println("----------------------");
Bundle bundle = msg.getData();
System.out.println("--> bundle: " + bundle.getStringArray("str").length);
}
};【总结】:这种方式也Android推荐使用的。但是我自己对这一部分的理解是:
如果是携带的是轻量级的int类型的数据或者对象的话,我们就用Message构造方法中自带的属性来传递。如果是需要携带上述两种类型之外的数据类型或者一些比较复杂的数据类型建议使用Bundle的方式来封装好后来传递。