本系列相关阅读
Android的消息机制主要是指Handler运行机制。由于Android开发规范明确表示只能在主线程更新UI,因此当子线程完成工作,我们需要使用Handler切换到主线程执行UI更新操作。
Handler的使用方式非常简单,我们只需要在主线程中创建Handler对象并重写handleMessage方法:
final SafeHandler safeHandler = new SafeHandler(this);
private static class SafeHandler extends Handler {
private WeakReference<Context> contextWeakReference;
public SafeHandler(Context context) {
this.contextWeakReference = new WeakReference<>(context);
}
@Override
public void handleMessage(Message msg) {
if (contextWeakReference != null) {
Context context = contextWeakReference.get();
if (context != null) {
//更新UI操作
switch (msg.what) {
case 0:
Toast.makeText(context, "更新UI", Toast.LENGTH_SHORT).show();
break;
case 1:
break;
default:
break;
}
}
}
super.handleMessage(msg);
}
}
然后在子线程中就可以发送消息提醒主线程更新UI:
new Thread(new Runnable() {
@Override
public void run() {
safeHandler.sendEmptyMessage(0);//子线程通知主线程更新UI
}
}).start();
Handler之所以能如此便捷地实现线程间的消息传递,当然离不开底层的MessageQueue和Looper的支持。
简单介绍一下它们:
-
MessageQueue 消息队列
用来缓存一系列待处理的消息,它的内部存储结构并不是真正的队列,而是采用单链表结构来存储消息列表。 -
Looper 循环
MessageQueue不能处理消息,这个工作由Looper来完成。它是以无限循环的形式去询问是否有新消息,如果有的话就处理,如果没有就一直等待。 -
ThreadLocal
一个线程内部的数据存储类,通过它可以在 指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据。【这是一篇详细介绍ThreadLocal的文章,点击查看】
我们知道,Handler在创建的时候会采用当前线程的Looper来构建消息循环系统,那么它是如何获取到当前线程的Looper的?答案就是使用ThreadLocal,通过ThreadLocal可以轻松获取每个线程的Looper。如果想继续了解如何获取线程Looper点击深入理解Android消息机制(三)原理分析。
有一点我们要注意:线程在默认情况下是没有Looper的,如果需要使用Handler就必须为线程创建Looper,否则系统会抛出异常 Can't create handler inside thread that has not called Looper.prepare()
。根据我们的开发经验,Android中的主线程是可以直接使用Handler的,因为系统在创建ActivityThread的时候会为主线程初始化Looper。
总结:本文简单地介绍一些消息机制基本概念,顺带着演示了Handler使用步骤,目的就是为了让大家对消息机制有个大致的了解,下一篇会介绍消息机制的具体流程。
下一篇:深入理解Android消息机制(二)Handler工作过程
参考
- 《Android开发艺术探索》
- https://www.jianshu.com/p/f2ff9c38c5be
网友评论