关闭BottomSheetDialogFragment时ComposeView报ViewTreeLifecycleOwner未找到崩溃
列表项中ComposeView在BottomSheetDialogFragment关闭后重绑崩溃问题
问题描述
我在RecyclerView的ViewHolder布局里使用了ComposeView,用于Fragment的列表项展示。但在显示并关闭BottomSheetDialogFragment后,ViewHolder项重新绑定时会触发崩溃。
崩溃日志
Fatal Exception: java.lang.IllegalStateException ViewTreeLifecycleOwner not found from com.google.android.material.card.MaterialCardView{cfc51a6 V.E...... ......ID 21,156-1059,642 #7f0a03f9 app:id/product} androidx.compose.ui.platform.AbstractComposeView.addView (ComposeView.android.kt:349) androidx.compose.ui.platform.WindowRecomposer_androidKt.createLifecycleAwareWindowRecomposer (WindowRecomposer_android.kt:349) androidx.compose.ui.platform.WindowRecomposer_androidKt.createLifecycleAwareWindowRecomposer$default (WindowRecomposer_android.kt:324) androidx.compose.ui.platform.WindowRecomposerFactory$Companion$LifecycleAware$1.createRecomposer (WindowRecomposerFactory.java:168) androidx.compose.ui.platform.WindowRecomposerPolicy.createAndInstallWindowRecomposer$ui_release (WindowRecomposerPolicy.java:224) androidx.compose.ui.platform.WindowRecomposer_androidKt.getWindowRecomposer (WindowRecomposer_android.kt:299) androidx.compose.ui.platform.AbstractComposeView.resolveParentCompositionContext (ComposeView.android.kt:242) androidx.compose.ui.platform.AbstractComposeView.ensureCompositionCreated (ComposeView.android.kt:249) androidx.compose.ui.platform.AbstractComposeView.createComposition (ComposeView.android.kt:194) androidx.compose.ui.platform.ComposeView.setContent (ComposeView.android.kt:420)
已尝试的操作
- 使用Fragment导航组件,将BottomSheetDialogFragment的导航节点从
<dialog>改为<fragment>后问题消失,但弹窗失去底部样式。 - appcompat和fragment-ktx依赖已更新至最新稳定版,Fragment由AppCompatActivity托管。
- 崩溃仅在关闭底部弹窗后重绑列表项时触发,正常滚动重绑不会出现。
- 当前ViewCompositionStrategy设置为
DisposeOnDetachedFromWindowOrReleasedFromPool。
问题原因及解决方法
原因分析
崩溃核心是ComposeView在重绑时无法找到ViewTreeLifecycleOwner,具体原因如下:
- BottomSheetDialogFragment关闭时,其内部的LifecycleOwner会被销毁,但RecyclerView的ViewHolder可能复用了之前关联到Dialog生命周期的View。
- 重绑时,ComposeView尝试从父View树自动查找LifecycleOwner,但此时父View的生命周期关联可能因Dialog关闭出现短暂断层,无法关联到宿主Fragment的有效LifecycleOwner。
DisposeOnDetachedFromWindowOrReleasedFromPool策略虽会在View脱离窗口或回收时释放Composition,但Dialog关闭后的重绑场景下,View可能未完全回收就被复用,导致Composition重建时找不到有效生命周期依赖。
解决方法
- 手动为ComposeView绑定LifecycleOwner
在ViewHolder的bind方法中,显式将ComposeView关联到宿主Fragment的viewLifecycleOwner,避免依赖父View树的自动查找:
// ViewHolder的bind方法内 composeView.setLifecycleOwner(fragment.viewLifecycleOwner) composeView.setContent { // 你的Compose内容实现 }
- 调整ViewCompositionStrategy策略
可将策略改为DisposeOnViewTreeLifecycleDestroyed,该策略会在ViewTree的LifecycleOwner销毁时才释放Composition,避免提前释放导致的生命周期关联问题,建议配合手动绑定LifecycleOwner使用:
composeView.setViewCompositionStrategy( ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed )
- BottomSheetDialog关闭后触发RecyclerView刷新
在BottomSheetDialogFragment关闭后,主动触发RecyclerView的刷新,确保ViewHolder重绑时View树的生命周期已恢复正常。可通过导航组件的返回回调实现:
// 宿主Fragment中监听Dialog关闭事件 findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<Boolean>("dialogClosed")?.observe(viewLifecycleOwner) { if (it) { recyclerView.adapter?.notifyDataSetChanged() } } // BottomSheetDialogFragment中关闭时发送通知 findNavController().previousBackStackEntry?.savedStateHandle?.set("dialogClosed", true)
- 清空ViewHolder复用前的ComposeView状态
在RecyclerView的onViewRecycled方法中,清空ComposeView的内容,确保复用前View处于干净状态:
override fun onViewRecycled(holder: MyViewHolder) { super.onViewRecycled(holder) holder.composeView.setContent { } }
内容的提问来源于stack exchange,提问作者SmallGrammer
相关产品推荐
相关产品推荐

