前言
一张图让你了解消息机制怎么实现 线程间通信。
重温了Android艺术开发探索这本书的消息机制,写这篇文章加入了博主自己的一些理解,换了些角度,希望能帮助对Android消息机制还不太理解的朋友们。若文章有不正确的地方,欢迎讨论,欢迎指出。
Android的消息机制主要是指Handler的运行机制。Handler的运行需要底层的MessageQueue和Looper的支撑。先简单介绍一下,MessageQueue是消息队列,用于存储一组消息(虽然叫消息队列,其实是用单链表的数据结构来存储消息列表)。Looper中文翻译为循环,这里可以理解为消息循环。它会无限循环访问消息队列中有没有新的消息需要处理。
那么这两个东西在哪里的呢?实际上又是怎么和Handler配合一起工作的呢?
Handler、MessageQueue和Looper大致的工作模型
这个模型是我自己理解的一个模型,上面画的是我们经常见到的一种情况,就是在子线程中更新UI时,发消息交给UI线程去更新的一种情况。这个实现的实际就是在子线程中拥有一个Handler对象,这个对象持有Looper的对象,那么这个Handler在post消息的时候,就知道它要发到哪个线程中执行了。
这里有几个需要注意的地方:
1. Looper不是每个线程中一定都拥有的。主线程例外,当应用程序启动的时候,就已经给主线程创建好一个Looper了。所以这就是为什么我们可以在主线程中直接使用Handler的原因。而其他新开的线程想拥有Looper的话,需要自己创建(这个主要是为了,可以让其他线程发消息给自己处理),创建Looper的方式,Looper.prepare()
。
2. Looper是对象是存放在线程对象的一个成员变量ThreadLocalMap中的一个数组中的,具体存放和获取的方式请阅读我的上一篇文章 Android消息机制(一)之 ThreadLocal
例子代码:
某个Activity,即主线程中
private String content=null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView=(TextView)findViewById(R.id.textView);
//创建属于主线程的handler,在主线成中创建,默认拥有主线程的Looper
handler=new Handler();
// 构建Runnable对象。在runnable中更新界面
Runnable runnableUi=new Runnable(){
@Override
public void run() {
//更新界面
textView.setText("the Content is:"+content);
}
};
//新创建一个线程,利用主线程的handler发送一个runnable对象,让主线程执行这段程序
new Thread(){
public void run(){
//注意,这里不用创建一个Looper,因为这个发给主线程的消息。和子线程的Looper没有关系
content=df.downLoadFiles();
handler.post(runnableUi);
}
}.start();
}
看了上面的示例代码就很好理解了。那么MessageQueue和Looper是怎么实现的呢?
MessageQueue的工作原理
MessageQueue的翻译是消息队列,上面说了,它实际上不是一个队列,它是通过一个单链表的数据结构来维护消息列表,单链表在插入和删除上比较有优势。
通过上面个工作模型分析,MessageQueue主要的工作就两个,插入和读取,分别对应enqueueMessage 和 next 方法。enqueueMessage 方法的作用是往消息队列中插入一条消息,而next的作用是从消息队列中取出一条消息并将其从消息队列中移出。