为何用runBlocking阻塞线程会导致悬浮窗无法正常工作?
class MyAccessibilityService : AccessibilityService() { override fun onServiceConnected() { super.onServiceConnected() windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager showOverlay() } private fun showOverlay() { // omitted about composeView code windowManager.addView(composeView, params) runBlocking(newSingleThreadContext("MyOwnThread")) { while (true) { delay(1000 * 10) windows.forEach { println(it) } } } } }
问题:在调用windowManager.addView后使用runBlocking阻塞线程,为何会导致悬浮窗无法正常工作?
我无法理解两者之间存在何种关联?
原因拆解
- 主线程被永久卡死:
onServiceConnected是在AccessibilityService的主线程(UI线程)中执行的,runBlocking的本质是阻塞当前调用它的线程——也就是这个主线程。哪怕你在runBlocking里开了新线程跑循环,runBlocking会一直等待内部协程结束,而你的while(true)是无限循环,导致主线程彻底被堵死。 - 悬浮窗初始化依赖主线程:
windowManager.addView只是把视图提交到窗口系统,后续视图的测量、布局、绘制全要在主线程完成。主线程被卡死,这些关键步骤根本跑不起来,悬浮窗自然无法显示或正常工作。 - Service核心逻辑瘫痪:AccessibilityService的所有核心回调(比如无障碍事件处理)都依赖主线程,主线程被堵死,整个Service的功能都会失效,悬浮窗作为Service的一部分当然也无法正常运作。
修复方案
把后台循环改成非阻塞的协程方式,不要占用主线程:
private val serviceScope = CoroutineScope(Dispatchers.IO + SupervisorJob()) private fun showOverlay() { // omitted about composeView code windowManager.addView(composeView, params) // 用独立协程跑后台循环,不阻塞主线程 serviceScope.launch { while (isActive) { // 用isActive判断协程状态,避免内存泄漏 delay(1000 * 10) windows.forEach { println(it) } } } } // Service销毁时取消协程,防止内存泄漏 override fun onDestroy() { super.onDestroy() serviceScope.cancel() }
内容的提问来源于stack exchange,提问作者SageJustus
相关产品推荐
相关产品推荐

