android - 为什么我在主线程中发布了一个 Runnable,但 Runnable 是在 HandlerThread 中执行的?
问题描述
这是有问题的代码:
object MainThreadPoster : Handler(Looper.getMainLooper()) {
fun postRunnableAtFixRate(runnable: Runnable, token: Any, delay: Long, period: Long) {
postAtTime(object : Runnable {
override fun run() {
runnable.run()
}
}, token, SystemClock.uptimeMillis() + delay)
}
}
MainThreadPoster 是用 mainLooper 初始化的,所以 runnable 函数(在 postRunnableAtFixRate 方法中)预计会在主线程中执行,但问题是 runnable 函数有时可能会在 HandlerThread 中执行。
这是预期的堆栈跟踪
这是有问题的堆栈跟踪
解决方案
不要在代码中调用 Message.recycle()。在Android 4.4中,如果多次调用Message.recycle(),消息会多次出现在消息池中,消息可能同时存在于多个消息队列中。</p>
这是 poc:
class MainActivity : AppCompatActivity() {
private val mMainHandler = Handler(Looper.getMainLooper())
private lateinit var mSubHandler: Handler
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn_test.setOnClickListener {
start()
}
val handlerThread = HandlerThread("sub thread")
handlerThread.start()
mSubHandler = Handler(handlerThread.looper)
}
private fun start(){
val message = Message()
message.recycle()
message.recycle()
mMainHandler.postDelayed({
if(Looper.myLooper() != Looper.getMainLooper()){
throw Exception("should run in main thread")
}
start()
}, 100)
mSubHandler.sendEmptyMessage(1)
}
}
推荐阅读
- javascript - 如何将 useState 变量的当前值存储在数组中?
- python - 网页抓取 - 如何提取 URL 中链接的类型?
- amazon-s3 - (InternalError) 在 boto3 中调用 SelectObjectContent 操作时
- flutter - Flutter:如何使用future builder构建一个无限列表,一次显示n条记录
- artificial-intelligence - 计算图的启发式
- java - 如何在 Java 中的测试结果中查看我的场景名称
- python - Python:根据 Key 和附加条件将聚合列添加到 DataFrame
- mysql - MySQL Query where - 第 1 列是重复的 - 第 2 列不是
- r - 如何仅舍入数据框中的数值?
- angular - angular ngFor trackBy 无法按预期工作