如何用LifecycleObserver实现onWindowFocusChanged()等效效果?
解决LifecycleObserver中实现类似onWindowFocusChanged的UI操作问题
核心问题原因
onResume() 是Activity生命周期回调,此时Activity已进入可见状态,但窗口(Window)可能尚未完成与系统的绑定、获取焦点,直接在此处执行Window相关操作(如添加悬浮窗、Toast)会因Window Token未就绪触发 WindowManager$BadTokenException。
可行解决方案
方案1:利用主线程消息队列延迟执行(最简单)
在onResume()中通过DecorView.post()将UI操作投递到主线程消息队列尾部,此操作会等待当前生命周期流程、窗口绘制等任务完成后执行,确保窗口已就绪。
class FocusLifecycleObserver(private val activity: Activity) : DefaultLifecycleObserver { override fun onResume(owner: LifecycleOwner) { super.onResume(owner) // 投递任务到消息队列尾部,等待窗口就绪 activity.window.decorView.post { // 此处执行你的窗口操作,比如添加悬浮窗 val overlayParams = WindowManager.LayoutParams().apply { type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY } else { WindowManager.LayoutParams.TYPE_PHONE } flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE width = WindowManager.LayoutParams.WRAP_CONTENT height = WindowManager.LayoutParams.WRAP_CONTENT gravity = Gravity.CENTER } val overlayView = LayoutInflater.from(activity).inflate(R.layout.layout_overlay, null) activity.windowManager.addView(overlayView, overlayParams) } } }
方案2:监听DecorView的附着状态
通过View.OnAttachStateChangeListener监听Activity的根布局(DecorView)是否已绑定到Window,当onViewAttachedToWindow回调触发时,说明窗口已完成绑定,可安全执行UI操作。
class FocusLifecycleObserver(private val activity: Activity) : DefaultLifecycleObserver { private val attachListener = object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View) { // DecorView已绑定到Window,窗口就绪 performWindowOperations() } override fun onViewDetachedFromWindow(v: View) { // 可在此处清理窗口资源 } } override fun onResume(owner: LifecycleOwner) { super.onResume(owner) activity.window.decorView.addOnAttachStateChangeListener(attachListener) } override fun onPause(owner: LifecycleOwner) { super.onPause(owner) // 移除监听,避免内存泄漏 activity.window.decorView.removeOnAttachStateChangeListener(attachListener) } private fun performWindowOperations() { // 执行窗口相关UI操作 } }
方案3:结合onWindowFocusChanged与LiveData传递状态
如果需要精确监听窗口焦点变化(不仅是首次就绪),可在Activity中重写onWindowFocusChanged,通过LiveData将焦点状态传递给LifecycleObserver。
// 定义焦点状态的LiveData class WindowFocusState : MutableLiveData<Boolean>() // Activity中实现焦点回调并发送状态 class MainActivity : AppCompatActivity() { val windowFocusState = WindowFocusState() override fun onWindowFocusChanged(hasFocus: Boolean) { super.onWindowFocusChanged(hasFocus) if (hasFocus) { windowFocusState.postValue(true) } } } // LifecycleObserver中观察状态变化 class FocusLifecycleObserver(private val focusState: WindowFocusState) : DefaultLifecycleObserver { private val focusObserver = Observer<Boolean> { hasFocus -> if (hasFocus == true) { performWindowOperations() } } override fun onCreate(owner: LifecycleOwner) { super.onCreate(owner) focusState.observe(owner, focusObserver) } private fun performWindowOperations() { // 执行窗口相关UI操作 } }
方案选择建议
- 仅需在Activity首次获焦时执行一次操作:优先选方案1,代码简洁且足够可靠。
- 需要监听窗口绑定状态的变化:选方案2。
- 需要多次响应窗口焦点变化(如Activity从后台切回前台获焦):选方案3。
内容的提问来源于stack exchange,提问作者Akari
相关产品推荐
相关产品推荐

