信件:Message
刚接触Android开发,子线程中进行数据处理完毕之后,如何将数据传到主线程让我困惑一段时间。那么如何将数据传到主线程呢?这需要借助Android的Handler传递消息机制,原理详见Handler、Looper、MessageQueue消息机制原理。
1、获取Message
通常在子线程中处理完毕,需要借助Message向主线程发送消息,通知主线程,
1.1、直接创建
构造函数直接创建Message实例:
Message message = new Message();
message.what = 1;1.2、obtain()对象池获取
推荐使用obtain()从消息池获取Message对象,而不是直接new一个新的Message对象:
Message message = Message.obtain();可以查看源码,知晓其中的实现方式,即便一开始没有Message对象可以获取,也会新建一个对象,所以不用担心使用Message.obtain()这个方法会得到一个为null的Message对象:
/**
* 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;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}而这里的sPool就是所谓的“对象池”,其中最大存放50个Message对象可以重复使用:
/** @hide */
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;仔细一看发现对象池sPool怎么是一个Message对象,难道不应该是一个集合吗?在继续追溯源码可以发现Message本身的实现就类似一个链表,保存了下一个Message对象的引用,当然这部分是不对外开放的,不能直接调用:
// sometimes we store linked lists of these things
@UnsupportedAppUsage
/*package*/ Message next;2、发送Message
有了Message对象,向其中存放数据等信息。往往通过Bundle类携带数据,关于Bundle后面介绍:Android“包裹”:Bundle。
2.1、包裹“消息”
除了可以给Message.what设置int类型的消息标志(一般都是这么做的),还可以向里面添加数据。借助Bundle类,Message.setData(Bundle data)方法向Message对象添加所需携带的数据:
Bundle bundle = new Bundle();
//可以添加各种基本类型的数据
bundle.putString("key", "data");
//还支持添加集合数据,不过其中的对象要实现Parcelable接口:<? extends Parcelable>
List<Parcelable> result = new ArrayList<>();
bundle.putParcelableArrayList("list", (ArrayList<? extends Parcelable>) result);
message.setData(bundle);给Bundle这个“包裹”塞了一堆数据之后直接调用Message.setData(Bundle)将“包裹”交给Message既可以了(这里是将Bundle赋值给了Message内部的一个Bundle data成员变量)。
Message还真是全能,Bundle也是能“装”,这些谷歌都做了大量的封装,方便开发者使用。
2.2、发送“消息”
好了最后数据都准备好了,直接发个消息个主线程的Handler对象:
mHandler.sendMessage(message);2.3、主线程处理“消息”
之后主线程的活就来了,实现定义好的在主线程等待已久的Handler:
private Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle bundle = msg.getData();
String str = bundle.getString("key");
List<Parcelable> result = bundle.getParcelableArrayList("list");
Map<String, String> map = (Map<String, String>) msg.obj;
}
};去Message消息中取出包裹:
Bundle bundle = msg.getData();从包裹中再取出数据,层层拆包,虽然麻烦,但是相比子线程和主线程的通信那可简化了很多:
String str = bundle.getString("key");
List<Parcelable> result = bundle.getParcelableArrayList("list")除了Bundle中的数据,别忘了Message本身也携带了一个Object通用“包裹”obj,可以用来携带一个任意类型的对象:
Map<String, String> map = (Map<String, String>) msg.obj;至此,如何从子线程将数据传递到主线程的方法大抵如此。至于底层的实现如Handler、Looper是如何协同完成这些的以后再深入研究。
参考博客:

