一、前言
学习Android基础知识,都离不开handler,最开始最基础的使用从Handler.post去发送一个消息,Android系统的设计中,为了保证UI渲染的一致性(本质上线程并发问题)和无卡顿体验。耗时的操作需要放在工作线程中执行(一般是开发者自行创建的子线程)、Ui更新放在主线程。这样从各自职责上来讲是非常清晰的,Handler的出现的一个核心目的,就是解决工作线程处理的数据如何传递给Ui线程进行使用。
**故而,**我们在研发中,子线程比如做耗时数据处理操作后,调用通过主线程创建的Handler发送数据消息,最终并由当前的Hander处理消息,实现子线程数据切换到主线程处理的逻辑。
这边文章内容,会深入去理解Android中的Handler机制。先列出这篇文章要解答分析的一个问题列表如下:
- Handler死循环为什么不会导致应用程序卡死?[答案在3.3节]
- MessageQueue的优先级队列是如何进行排序的?[答案在2.1节]
- Message的数据结构是什么?如何保证线程安全的?[答案在2.1节]
- 如何创建Message对象?【答案在3.1节】
- 一个线程有几个Handler?如何实现这个机制的?[答案在2.2.3节]
- 为什么主线程可以直接new Handler进行使用,子线程中new Handler如何操作?[答案在2.2.3节]
- 为什么Handler容易出现内存泄漏?【答案在3.2节】
- Handler、Looper、MessageQueue、message之间的关系?【答案在4节】
接下来的文章内容,会从Handler的知识体系的三条主线问题进行展开
- Handler的请求发送到哪里去了?
- Handler的请求是如何被处理的?
- Handler,Looper,MessageQueue、Message之间的关系?
注:文章中涉及到的framework层的源码版本为android29!!!
二、原理源码解析
2.1Handler请求发送
首先我们还是从一个最简单的Demo入手
public class MainActivity extends AppCompatActivity {
private static final int HANDLER_FLAG = 666;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
//此处通过handler发送一个空消息
mHandler.sendEmptyMessageDelayed(HANDLER_FLAG, 1000);
}
}
handler发送消息的方法有多个,如sendMessageDelayed、sendMessage、sendEmptyMessage等,追踪源码最终都会调用到Handler中的sendMessageAtTime():
public class Handler {
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
//构建Message对象,通过Message.obtain()获得
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
/**
* 根据绝对时间将message加入到message queue中.
* @param uptimeMillis 消息被分发的绝对时间
* @return Returns true 消息被成功的入队,表示之后将被执行。如果未执行前,looper退出,则
* 消息终止执行。
*/
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
//获取到了主线程的Message queue 后文会有对mQueue的创建分析
MessageQueue queue = mQueue;
//queue为空的异常处理
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this