提到Handler,我们都会想到可以用来在子线程给UI线程发送消息,常用来子线程刷新UI。 而往深了问,你一定还知道Handler会绑定到一个Looper,而每个Looper会和一个MessageQ关联,从而达到向指定线程发送消息的功能。除此之外,还了解多少? 提到MessageQueue
,就不得不聊到Android的消息处理机制。
Handler消息处理机制
Android的消息机制,涉及到Handler
、Looper
、Message
和MessageQueue
。
Handler
是用于处理Message
的对象。它通常与一个特定的线程(通常是主线程)关联。通过Handler开发者可以将Message发送到与其关联的线程的消息队列中,以便在那个线程中执行处理。Message
是一个包含要传递的数据和指令的的对象。当需要在不同线程之间传递数据或执行行任务时,通常会创建一个Message
并将其发送给Handler
。Looper
是一个用于管理线程的消息队列别的对象。每个线程都可以有一个Looper
,它会在线程上创建一个消息队列,允许该线程接收并处理Message
。主线程通常已经具有一个默认的Looper
,而其他线程需要显式创建一个Looper
。MessageQueue
即是消息队列。是一个FIFO(先进先出)队列,用于存储待处理的Message
。每个Looper
都有一个关联的MessageQueue
,Handler
将Message
发送到这个队列中,然后由Looper
依次处理队列中的Message
。
简易的消息处理机制流程图
sequenceDiagram
Developer->>Looper: Looper@prepare
Looper ->> Looper: 循环取消息
Looper->>Handler:Handler@dispatchMessage
Looper->>MessageQueue: Looper@loop
MessageQueue->> MessageQueue: Message@next
MessageQueue->>JNI:nativePollOnce
Note Over JNI:native处理MessageQ及Looper
Handler-->>Developer:Message@Callback
Handler-->>Developer:Handler#Callback
Handler-->>Developer:Handler#handleMessage
Looper->>MessageQueue:Message@recycerUnchecked
Developer->>Handler:Message@obtain
Handler->>Handler:Handler@enqueueMessage
Handler->>MessageQueue:
MessageQueue-->>MessageQueue:MessageQueue@enqueueMessage
MessageQueue ->> JNI:nativeWake
MessageQueue
从上面的描述,我们可以MessageQueue
会按照一定的规则取出要执行的Message
,当消息执行完之后Message
就会被回收。
那么下面我们就通过代码来验证几种情况:
Message#Obtain
创建消息的消息和直接New Message
的方法创建消息,是否都会被回收- 如果消息对象被持有,是否消息也会被回收
- 如果接受消息在主线程,那么在
View#post
方法执行后,消息是否会被回收 - 如果接收消息在主线程,那么当切换到其他线程执行任务后,消息是否会被回收
- 如果接受消息在主线程,通过
Kotlin Coroutine
执行任务在Dispatchers.Main
或Dispatchers.Default
后,消息是否会被回收
通过Message#Obtain创建消息并发送
ini
Message.obtain(). also { it.what = 1 mObtainMsg = it mHandler.sendMessage(it) }
通过直接New的方法创建消息并发送
scss
Message().also {
it.what = 2
mHandler.sendMessage(it)
}
发送消息后打印消息信息
kotlin
class MyHandler(private val actRef: WeakReference<TestMessageActivity>) :
Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
val act = actRef.get() ?: return
Log.d(TAG, "msg:$msg}")
Log.d(TAG, "mObtainMsg:${act.mObtainMsg}}")
act.mSWThread.post {
Log.d(TAG, "msg--post:$msg}")
Log.d(TAG, "mObtainMsg--post:${act.mObtainMsg}}")
}
if (act.mSWThread.isChecked) {//是否开启了子线程
Thread {
Log.d(TAG, "thread--msg:$msg}")
Log.d(TAG, "thread--mObtainMsg:${act.mObtainMsg}}")
Thread.sleep(3000L)
Log.d(TAG, "threadAfter--msg:$msg}")
Log.d(TAG, "threadAfter--mObtainMsg:${act.mObtainMsg}}")
} .start()
}
if (act.mSWCoroutine.isChecked) {//是否开启协程
GlobalScope.launch(Dispatchers.Main) {
Log.d(TAG, "launchMain----msg:$msg}")
Log.d(TAG, "launchMain--mObtainMsg:${act.mObtainMsg}}")
}
GlobalScope.launch {
Log.d(TAG, "launch--msg:$msg}")
Log.d(TAG, "launch--mObtainMsg:${act.mObtainMsg}}")
}
}
}
}
Obtain创建消息发送消息,收到的日志结果
ini
2024-03-22 16:32:04.780 21621-21621/com.lotus.duode.myapplication D/TestMessageActivity: msg:{ when=-1ms what=1 target=com.lotus.duode.myapplication.TestMessageActivity$MyHandler }}
2024-03-22 16:32:04.780 21621-21621/com.lotus.duode.myapplication D/TestMessageActivity: mObtainMsg:{ when=-1ms what=1 target=com.lotus.duode.myapplication.TestMessageActivity$MyHandler }}
2024-03-22 16:32:04.781 21621-22106/com.lotus.duode.myapplication D/TestMessageActivity: thread--msg:{ when=-2ms what=1 target=com.lotus.duode.myapplication.TestMessageActivity$MyHandler }}
2024-03-22 16:32:04.781 21621-22106/com.lotus.duode.myapplication D/TestMessageActivity: thread--mObtainMsg:{ when=-2ms what=1 target=com.lotus.duode.myapplication.TestMessageActivity$MyHandler }}
2024-03-22 16:32:04.803 21621-22108/com.lotus.duode.myapplication D/TestMessageActivity: launch--msg:{ when=-19ms callback=android.view.Choreographer$FrameDisplayEventReceiver target=android.view.Choreographer$FrameHandler }}
2024-03-22 16:32:04.803 21621-22108/com.lotus.duode.myapplication D/TestMessageActivity: launch--mObtainMsg:{ when=-19ms callback=android.view.Choreographer$FrameDisplayEventReceiver target=android.view.Choreographer$FrameHandler }}
2024-03-22 16:32:04.806 21621-21621/com.lotus.duode.myapplication D/TestMessageActivity: msg--post:{ when=-2d2h37m50s923ms barrier=0 }}
2024-03-22 16:32:04.806 21621-21621/com.lotus.duode.myapplication D/TestMessageActivity: mObtainMsg--post:{ when=-2d2h37m50s923ms barrier=0 }}
2024-03-22 16:32:04.806 21621-21621/com.lotus.duode.myapplication D/TestMessageActivity: launchMain----msg:{ when=-2d2h37m50s923ms barrier=0 }}
2024-03-22 16:32:04.806 21621-21621/com.lotus.duode.myapplication D/TestMessageActivity: launchMain--mObtainMsg:{ when=-2d2h37m50s923ms barrier=0 }}
2024-03-22 16:32:07.782 21621-22106/com.lotus.duode.myapplication D/TestMessageActivity: threadAfter--msg:{ when=-2d2h37m53s899ms barrier=0 }}
2024-03-22 16:32:07.782 21621-22106/com.lotus.duode.myapplication D/TestMessageActivity: threadAfter--mObtainMsg:{ when=-2d2h37m53s899ms barrier=0 }}
New Message创建消息发送消息,收到的日志结果
ini
2024-03-22 16:32:27.427 21621-21621/com.lotus.duode.myapplication D/TestMessageActivity: msg:{ when=-9ms what=2 target=com.lotus.duode.myapplication.TestMessageActivity$MyHandler }}
2024-03-22 16:32:27.428 21621-21621/com.lotus.duode.myapplication D/TestMessageActivity: mObtainMsg:{ when=-2ms callback=android.view.Choreographer$FrameDisplayEventReceiver target=android.view.Choreographer$FrameHandler }}
2024-03-22 16:32:27.428 21621-22116/com.lotus.duode.myapplication D/TestMessageActivity: thread--msg:{ when=-10ms what=2 target=com.lotus.duode.myapplication.TestMessageActivity$MyHandler }}
2024-03-22 16:32:27.428 21621-22116/com.lotus.duode.myapplication D/TestMessageActivity: thread--mObtainMsg:{ when=-3ms callback=android.view.Choreographer$FrameDisplayEventReceiver target=android.view.Choreographer$FrameHandler }}
2024-03-22 16:32:27.428 21621-22108/com.lotus.duode.myapplication D/TestMessageActivity: launch--msg:{ when=-2d2h38m13s545ms barrier=0 }}
2024-03-22 16:32:27.428 21621-22108/com.lotus.duode.myapplication D/TestMessageActivity: launch--mObtainMsg:{ when=-3ms callback=android.view.Choreographer$FrameDisplayEventReceiver target=android.view.Choreographer$FrameHandler }}
2024-03-22 16:32:27.430 21621-21621/com.lotus.duode.myapplication D/TestMessageActivity: msg--post:{ when=-1ms callback=android.view.Choreographer$$ExternalSyntheticLambda0 target=android.view.Choreographer$FrameHandler }}
2024-03-22 16:32:27.430 21621-21621/com.lotus.duode.myapplication D/TestMessageActivity: mObtainMsg--post:{ when=-2d2h38m13s547ms barrier=0 }}
2024-03-22 16:32:27.430 21621-21621/com.lotus.duode.myapplication D/TestMessageActivity: launchMain----msg:{ when=-2ms callback=android.view.Choreographer$$ExternalSyntheticLambda0 target=android.view.Choreographer$FrameHandler }}
2024-03-22 16:32:27.430 21621-21621/com.lotus.duode.myapplication D/TestMessageActivity: launchMain--mObtainMsg:{ when=-2d2h38m13s547ms barrier=0 }}
2024-03-22 16:32:30.429 21621-22116/com.lotus.duode.myapplication D/TestMessageActivity: threadAfter--msg:{ when=-2d2h38m16s546ms barrier=0 }}
2024-03-22 16:32:30.429 21621-22116/com.lotus.duode.myapplication D/TestMessageActivity: threadAfter--mObtainMsg:{ when=-2d2h38m16s546ms barrier=0 }}
结论
通过Handler#handleMessage
接收的消息,在消息执行完成之后。如果后续有新的消息需要被使用,那么系统会通过Message#obtain
创建消息时,就会从Message#
sPool
中进行复用。
而消息的回收是在DispatchMessage完成之后。
因此如果我们需要持久化使用Message中的信息时,就需要使用变量对这些信息进行存储。