无冥冥之志者,无昭昭之明;无惛惛之事者,无赫赫之功。
解释:没有专心致志地刻苦学习,就没有融会贯通的智慧;没有埋头执着的工作,就不会取得显著的成就。
Handler消息机制
Handler消息机制是Android中普遍使用的一种机制。在Android开发中,不管是系统开发还是应用开发都必须了解的一种机制。
1. 用来干什么?
Handler消息机制是用来进行 线程之间 通信的。Android有一个重要的特点,那就是需要在主线程才能进行UI界面的更新,而对于一些特殊的场景,比如在子线程中获取到数据需要更新到UI界面,就必须进行线程间的通信,通过把数据交给主线程,由主线程进行UI更新。
在Android开发过程中,为了不影响UI界面的操作流程性,常常会创建工作线程去完成耗时操作,然后将耗时操作的结果返回给主线程,因此线程之间的通信是很重要的。
2.怎么用?使用过程中有什么注意点?
Handler的使用非常简单,步骤如下:
- 在Activity创建Handler对象:创建对象的时候需要重写handleMessage方法。
Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
//处理消息
}
};
- 发送消息
new Thread(new Runnable() {
@Override
public void run() {
Message msg = new Message();
handler.sendMessage(msg);
}
}).start();
上述三个步骤就是Handler的简单使用。Handler的创建在主线程中进行,重写的handleMessage方法中的参数就是需要处理的消息。需要处理的消息是在子线程中发出的,最终在主线程中(handleMessage方法)得到处理,这就完成了线程间通信。
Activity中可以如此简单的使用Handler得益于系统在主线程给我们初始化了Handler消息机制的一些工作。
注意点
上边Handler的使用仍存在需要注意的地方,那就是 内存泄露 问题,这个问题留到后文去解决。
3.实现原理?原理学习过程中,有什么收获?
通过源码的阅读学习,Handler的实现原理涉及到的类:
- Handler:Handler负责往这个消息队列存放消息,或者处理Looper取出来的消息
- Looper:负责监控消息队列中是否有消息需要处理。
- MessageQueue:消息队列,存放等待处理的消息。
- Message:作为消息的承载主体,当需要使用Handler消息机制的时候,首先需要使用Message记录需要传递消息的内容。
Handler消息机制的流程
Handler消息机制的实现流程是:首先,调用Looper的 *prepare 方法;它是一个静态方法,在这个方法中,会创建一个Looper对象,并把这个对象存放在ThreadLocal中,这样做的目的是确保一个线程只能有一个Looper对象。在Looper的构造函数中,会创建一个MessageQueue对象。这样MessageQueue和Looper都准备好了。接着是创建Handler对象,并且重写 handleMessage 方法,这个方法用于接收待处理的消息对象。最后,调用Looper的 loop 方法,这个方法开启一个死循环,不断的从Message Queue中获取消息。如果MessageQueue没有消息需要处理,线程进行休眠;如果有消息需要处理,那么消息将被取出来,交给Handler的handleMessage*进行处理。Handler消息机制流程就是这样运行的。源代码太多了,不打算这文章中贴源代码
在阅读源码的过程中,我对Handler消息机制流产生了一些问题:
- 为什么在子线程用handler的sendMessage发送类消息,就能传递到主线程类呢?
- Looper的loop方法是一个死循环,那么它不是一直运行着的吗?休眠是一个什么状态?
- loop方法既然休眠了,那么当有消息需要处理的时候,它又是怎么样被唤醒的呢?
第一个问题:子线程发送消息的时候,使用的是主线程中创建的Handler,那么使用主线程的Handler发送消息,最终消息回到走的是主线程的Handle消息机制。那么为什么子线程可以使用主线程创建的Handler?这是因为线程资源共享。
其他两个问题需要深入底层才能找到答案。
注意点:
一、常见的创建Message的方式:
- Message msg = new Message();
- Message msg = message.obtain();
- Message msg = handler.ontainMessage();
以new的方法直接创建message就像新创建一个对象一样,需要重新申请内存。而以message.obtain和handler.ontainMessage的方式创建Message,得到的Message对象是重对象池中得到的,这种方式可以避免过多创建对象。
二、内存泄露
Handler的内存泄露问题的原因在于使用下面语句创建Handler的时候,内部类持有外部类的引用。
Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
//处理消息
}
};
当Activity需要,由于Handler对象持有Activity的引用,导致Activity和Handler对象都不能被回收,引发了内存泄露。那么正确的做法是:把Handler定义成静态内部类,最好在Handler类内部使用弱引用持有Activity 的引用。
static class MyHandler extends Handler{
WeakReference<Activity> weakReference;
public MyHandler(Activity a){
weakReference = new WeakReference<>(a);
}
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Activity a = weakReference.get();
}
}
Handler的消息机制暂时写到这,还有一些问题没有解决,知识点也还不够全面,这些内容在后续会相继补上。