1. Handler使用
在Activity中实例化一个Handler并实现他的handleMessage方法,然后在需要调用的地方通过使用send和post系列方法,就可以轻松的将一个任务切换到Handler所在的线程中去,如下:
private val handler: Handler = object : Handler() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
}
}
handler.send*();
handler.post*();
so easy!
然而,你真的了解Handler了吗,真的用好了吗,真的没有踩过Handler的坑?带着这些疑问,我们今天再来重新认识下Handler。
2. 消息机制的模型和架构
消息机制主要包含以下4个部分:Handler、Message、Looper、MessageQueue;下面我们一一介绍:
- Handler:消息辅助类,主要功能是向消息池发送各种消息事件;
- Message:需要传递的消息及数据的载体;
- Looper:不断循环执行(Looper.loop()),从MessageQueue中读出消息,按分发机制分发给不同的消息处理者;
- MessageQueue:消息队列,内部是通过一个单链表实现的,主要作用是向消息池投递消息(MessageQueue.enqueueMessage)和取走消息(MessageQueue.next)。
3. 消息机制源码分析
- 在主线程创建Handler后,ThreadLocal会自动调用Looper.prepare()创建Looper;
- 通过send或post方法发送消息后,最终通过sendMessageAtTime中的enqueueMessage方法将消息发送到消息池中;
- 在Looper中启动循环,通过loop()方法不断获取消息;
- 拿到消息后通过msg.target.dispatchMessage将消息分发到目标Handler中进行处理
4. 消息机制如何引起内存泄漏及解决方案
- 引起原因:Handler允许我们发送延时消息,在延时期间关闭了Activity,这时因为Message会持有Handler,另外Java特性内部类会持有外部类,使得Handler会持有Activity,最终导致泄漏。
- 解决方案:将Handler定义成静态内部类,在内部持有Activity弱引用,同时及时移除所有消息,代码如下:
private val handler = SafeHandler(this)
private class SafeHandler(activity: Activity?) : Handler() {
private val ref: WeakReference<Activity?>
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
if (ref.get() != null) {
}
}
init {
ref = WeakReference(activity)
}
}
override fun onDestroy() {
super.onDestroy()
handler.removeCallbacksAndMessages(null)
}
5. 如何在子线程中更新UI
- Toast和Dialog在子线程中弹出
Thread(Runnable {
Looper.prepare()
Toast.makeText(this, "不会崩溃啦!", Toast.LENGTH_SHORT).show()
Looper.loop()
})
- 通过在子线程中将数据post出来再执行
UiHandler.run(runnable);
6. Looper机制妙用
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.NonNull;
public final class UiHandler {
private UiHandler(){
}
private static final Handler HANDLER = new Handler(Looper.getMainLooper());
public static void run(@NonNull Runnable runnable) {
if (isMainThread()) {
runnable.run();
}else{
HANDLER.post(runnable);
}
}
public static boolean isMainThread() {
return Looper.myLooper() == Looper.getMainLooper();
}
}
7. Handler延伸
- AsyncTask:
- HandlerThread:
- Messager:
- IdleHandler:
- IntentService:
上述Handler延伸可自行查找资料,这里不再一一讲述
8.自己实现一套消息机制
通过上面的分析,我们是否可以参考源码,试着自己实现一套简单的消息机制呢,欢迎大家踊跃参与!
网友评论