Android Fragment中addMenuProvider传入viewLifecycleOwner与RESUMED的作用
addMenuProvider有多个重载方法,你用的是不指定生命周期的版本,而带viewLifecycleOwner和Lifecycle.State.RESUMED的版本是更贴合Fragment场景的写法,两者核心差异在于生命周期绑定和菜单生效时机。
1. viewLifecycleOwner的作用
Fragment存在两个独立的生命周期:
- 自身生命周期:从
attach到detach - 视图生命周期:从
onCreateView到onDestroyView
viewLifecycleOwner是Fragment视图生命周期的持有者,把它传给addMenuProvider后:
- MenuProvider的生命周期会和Fragment的视图绑定,当Fragment视图被销毁(比如Fragment被隐藏、从回退栈弹出),MenuProvider会自动从Activity中移除,不会残留。
- 能避免视图销毁后,菜单还留在ActionBar上,或点击菜单时触发已销毁Fragment的逻辑(比如调用已释放的View引发空指针)。
如果不传这个参数,MenuProvider默认绑定Activity的生命周期——只要Activity没销毁,这个MenuProvider就一直存在。哪怕你的Fragment已经被销毁、视图不存在了,它添加的菜单仍会显示在ActionBar上,容易引发意外问题。
2. Lifecycle.State.RESUMED的作用
这个参数用来指定MenuProvider生效的最小生命周期状态:
- 传入
RESUMED意味着,只有当Fragment的视图处于RESUMED状态(Fragment可见且可交互,比如用户能正常点击屏幕)时,菜单才会被创建并显示。 - 如果Fragment处于
STARTED状态(可见但不可交互,比如被Dialog遮挡、处于分屏的非活跃窗口),MenuProvider会暂停工作,菜单会被隐藏。
如果不传这个参数,默认最小状态是Lifecycle.State.STARTED——只要Fragment的视图可见(哪怕不可交互),菜单就会显示出来。
为什么你移除后没发现变化?
这是因为你的测试场景没触发生命周期边界情况:
- 如果你一直让Fragment处于可见可交互状态,视图从未销毁过,绑定Activity生命周期还是Fragment视图生命周期的差异不会体现出来。
- 你没测试过Fragment被隐藏、视图销毁的场景,所以看不到菜单残留的问题;也没测试过Fragment处于不可交互的
STARTED状态,菜单显示时机的差异也没暴露。
推荐的Fragment场景写法
在Fragment中添加MenuProvider时,建议绑定viewLifecycleOwner并指定RESUMED状态,避免生命周期不一致导致的问题:
private fun addOptionMenu() { val activity = requireActivity() activity.addMenuProvider(object : MenuProvider{ override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { menuInflater.inflate(R.menu.edit_menu, menu) } override fun onMenuItemSelected(menuItem: MenuItem): Boolean { return when(menuItem.itemId){ R.id.action_next -> { // 处理下一步逻辑 true } R.id.action_settings -> { // 处理设置逻辑 true } else -> false } } }, viewLifecycleOwner, Lifecycle.State.RESUMED) }
内容的提问来源于stack exchange,提问作者Abdelrhman Ghanem
相关产品推荐
相关产品推荐

