- 一、简介
- 二、消息机制的模型
- 三、消息机制的架构
- 四、消息机制的源码解析
- 1.Looper
- 2.Handler
- 3. 发送消息
- 4. 获取消息
- 5. 分发消息
提起 Android 消息机制,想必都不陌生。其中包含三个部分:Handler,MessageQueue 以及 Looper,三者共同协作,完成消息机制的运行。
一、简介在 Android 中使用消息机制,我们首先想到的就是 Handler 。没错,Handler 是 Android 消息机制的上层接口。Handler 的使用过程很简单,通过它可以轻松地将一个任务切换到 Handler 所在的线程中去执行。通常情况下,Handler 的使用场景就是更新 UI 。
public class TestActivity extends AppCompatActivity {
private static final String TAG = "TestActivity";
private Handler mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Log.d(TAG, msg.what + "");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
new Thread(new Runnable() {
@Override
public void run() {
Message message = Message.obtain();
message.what = 1;
mHandler.sendMessage(message);
}
}).start();
}
}
在子线程中,进行耗时操作,执行完操作后,发送消息,通知主线程更新 UI。这便是消息机制的典型应用场景。我们通常只会接触到 Handler 和 Message 来完成消息机制,其实内部还有两大助手来共同完成消息传递。
二、消息机制的模型-
消息(Message) 需要传递的消息,可以传递数据;
-
消息队列(Message Queue) 消息队列,但是它的内部实现并不是用的队列,实际上是通过一个单链表的数据结构来维护消息列表,因为单链表在插入和删除上比较有优势。主要功能向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next);
-
处理者(Handler) 消息辅助类,主要功能向消息池发送各种消息事件(Handler.sendMessage)和处理相应消息事件(Handler.handleMessage)
-
循环器(Looper) 不断循环执行(Looper.loop),从MessageQueue中读取消息,按分发机制将消息分发给目标处理者。
消息机制的运行流程:在子线程执行完耗时操作,当 Handler
发送消息时,将会调用MessageQueue.enqueueMessage
,向消息队列中添加消息。当通过Looper.loop
开启循环后,会不断地从线程池中读取消息,即调用MessageQueue.next
,然后调用目标Handler
(即发送该消息的Handler)的dispatchMessage
方法传递消息,然后返回到Handler
所在线程,目标Handler
收到消息,调用handleMessage
方法,接收消息,处理消息。 MessageQueue,Handler 和 Looper 三者之间的关系:每个线程中只能存在一个 Looper,Looper是保存在 ThreadLocal 中的。主线程(UI线程)已经创建了一个 Looper ,所以在主线程中不需要再创建 Looper ,但是在其他线程中需要创建 Looper 。每个线程中可以有多个 Handler ,即一个 Looper 可以处理来自多个 Handler 的消息。 Looper 中维护一个 MessageQueue ,来维护消息队列,消息队列中的 Message 可以来自不同的 Handler 。
下面是消息机制的整体架构图
要想使用消息机制,首先要创建一个 Looper。 初始化 Looper 无参情况下,默认调用 prepare(true) ;表示的是这个Looper可以退出,而对于false的情况则表示当前Looper不可以退出。
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
这里看出,不能重复创建 Looper,只能创建一个。创建 Looper,并保存在 ThreadLocal 。其中 ThreadLocal 是线程本地存储区(Thread Local Storage,简称为TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的 TLS 区域。
开启 Looper
public static void loop() {
final Looper me = myLooper(); //获取TLS存储的Looper对象
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; //获取Looper对象中的消息队列
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) { //进入loop的主循环方法
Message msg = queue.next(); //可能会阻塞,因为next()方法可能会无限循环
if (msg == null) { //消息为空,则退出循环
return;
}
Printer logging = me.mLogging; //默认为null,可通过setMessageLogging()方法来指定输出,用于debug功能
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg); //获取msg的目标Handler,然后用于分发Message
if (logging != null) {
logging.println("
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?