RecyclerView中ComposeView调用setContent触发ViewTreeLifecycleOwner未找到异常
RecyclerView中使用ComposeView触发ViewTreeLifecycleOwnerNotFound崩溃的解决方案
我在RecyclerView的列表项中使用ComposeView,在RecyclerView.Adapter的onBindViewHolder方法里调用ComposeView.setContent(),但偶尔会触发以下崩溃:
Fatal Exception: java.lang.IllegalStateException: ViewTreeLifecycleOwner not found from android.widget.FrameLayout{cf04e92 VFE...C.. ......ID 0,599-1768,808 #7f0b05f5 app:id/root_container} at androidx.compose.ui.platform.WindowRecomposer_androidKt.createLifecycleAwareViewTreeRecomposer(WindowRecomposer_android.kt:244) at androidx.compose.ui.platform.WindowRecomposer_androidKt.access$createLifecycleAwareViewTreeRecomposer(WindowRecomposer_android.kt:1) at androidx.compose.ui.platform.WindowRecomposerFactory$Companion$LifecycleAware$1.createRecomposer(WindowRecomposerFactory.java:99) at androidx.compose.ui.platform.WindowRecomposerPolicy.createAndInstallWindowRecomposer$ui_release(WindowRecomposerPolicy.java:155) at androidx.compose.ui.platform.WindowRecomposer_androidKt.getWindowRecomposer(WindowRecomposer_android.kt:230) at androidx.compose.ui.platform.AbstractComposeView.resolveParentCompositionContext(AbstractComposeView.java:244) at androidx.compose.ui.platform.AbstractComposeView.ensureCompositionCreated(AbstractComposeView.java:251) at androidx.compose.ui.platform.AbstractComposeView.createComposition(AbstractComposeView.java:196) at androidx.compose.ui.platform.ComposeView.setContent(ComposeView.java:426) at a.b.c.f.s.viewholders.S.bind(S.java:154) at a.b.c.f.f.RvAdapter.onBindViewHolder(ForYouRvAdapter.java:48) at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7337) at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6194) at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6460) at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6300) at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6296) at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2330) at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1631) at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1591) at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:668) at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4309) at androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:3686) at android.view.View.measure(View.java:27720) at androidx.constraintlayout.widget.ConstraintLayout$Measurer.measure(ConstraintLayout.java:811) at androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.measure(BasicMeasure.java:466) at androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.measureChildren(BasicMeasure.java:134) at androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.solverMeasure(BasicMeasure.java:278) at androidx.constraintlayout.core.widgets.ConstraintWidgetContainer.measure(ConstraintWidgetContainer.java:120) at androidx.constraintlayout.widget.ConstraintLayout.resolveSystem(ConstraintLayout.java:1594) at androidx.constraintlayout.widget.ConstraintLayout.onMeasure(ConstraintLayout.java:1708) at android.view.View.measure(View.java:27720) at androidx.core.widget.NestedScrollView.measureChildWithMargins(NestedScrollView.java:1792) at android.widget.FrameLayout.onMeasure(FrameLayout.java:194) at androidx.core.widget.NestedScrollView.onMeasure(NestedScrollView.java:627) at android.view.View.measure(View.java:27720) at androidx.swiperefreshlayout.widget.SwipeRefreshLayout.onMeasure(SwipeRefreshLayout.java:705) at android.view.View.measure(View.java:27720) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:7352) at androidx.coordinatorlayout.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:760) at androidx.coordinatorlayout.widget.CoordinatorLayout.onMeasure(CoordinatorLayout.java:833) at android.view.View.measure(View.java:27720) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:7352) at android.widget.FrameLayout.onMeasure(FrameLayout.java:194) at android.view.View.measure(View.java:27720) at androidx.recyclerview.widget.RecyclerView$LayoutManager.measureChildWithMargins(RecyclerView.java:9681) at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1657) at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1591) at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:668) at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4309) at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:4012) at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4578) at android.view.View.layout(View.java:24969) at android.view.ViewGroup.layout(ViewGroup.java:6784) at androidx.viewpager2.widget.ViewPager2.onLayout(ViewPager2.java:527) at android.view.View.layout(View.java:24969) at android.view.ViewGroup.layout(ViewGroup.java:6784) at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1873) at android.view.View.layout(View.java:24969) at android.view.ViewGroup.layout(ViewGroup.java:6784) at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1873) at android.view.View.layout(View.java:24969) at android.view.ViewGroup.layout(ViewGroup.java:6784) at androidx.coordinatorlayout.widget.CoordinatorLayout.layoutChild(CoordinatorLayout.java:1213) at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayoutChild(CoordinatorLayout.java:899) at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:919) at android.view.View.layout(View.java:24969) at android.view.ViewGroup.layout(ViewGroup.java:6784) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332) at android.widget.FrameLayout.onLayout(FrameLayout.java:270) at android.view.View.layout(View.java:24969) at android.view.ViewGroup.layout(ViewGroup.java:6784) at androidx.recyclerview.widget.RecyclerView$LayoutManager.layoutDecoratedWithMargins(RecyclerView.java:9878) at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1689) at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1591) at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:668) at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4309) at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:4012) at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4578) at android.view.View.layout(View.java:24969) at android.view.ViewGroup.layout(ViewGroup.java:6784) at androidx.viewpager2.widget.ViewPager2.onLayout(ViewPager2.java:527) at android.view.View.layout(View.java:24969) at android.view.ViewGroup.layout(ViewGroup.java:6784) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673) at android.widget.LinearLayout.onLayout(LinearLayout.java:1582) at android.view.View.layout(View.java:24969) at android.view.ViewGroup.layout(ViewGroup.java:6784) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332) at android.widget.FrameLayout.onLayout(FrameLayout.java:270) at android.view.View.layout(View.java:24969) at android.view.ViewGroup.layout(ViewGroup.java:6784) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332) at android.widget.FrameLayout.onLayout(FrameLayout.java:270) at android.view.View.layout(View.java:24969) at android.view.ViewGroup.layout(ViewGroup.java:6784) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673) at android.widget.LinearLayout.onLayout(LinearLayout.java:1582) at android.view.View.layout(View.java:24969) at android.view.ViewGroup.layout(ViewGroup.java:6784) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332) at android.widget.FrameLayout.onLayout(FrameLayout.java:270) at android.view.View.layout(View.java:24969) at android.view.ViewGroup.layout(ViewGroup.java:6784) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673) at android.widget.LinearLayout.onLayout(LinearLayout.java:1582) at android.view.View.layout(View.java:24969) at android.view.ViewGroup.layout(ViewGroup.java:6784) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332) at android.widget.FrameLayout.onLayout(FrameLayout.java:270) at com.android.internal.policy.DecorView.onLayout(DecorView.java:1432) at android.view.View.layout(View.java:24969) at android.view.ViewGroup.layout(ViewGroup.java:6784) at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:4917) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:4240) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:3116) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:10885) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1301) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1309) at android.view.Choreographer.doCallbacks(Choreographer.java:923) at android.view.Choreographer.doFrame(Choreographer.java:852) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1283) at android.os.Handler.handleCallback(Handler.java:942) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:226) at android.os.Looper.loop(Looper.java:313) at android.app.ActivityThread.main(ActivityThread.java:8757) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
当前使用的Compose版本为androidx.compose.ui:ui:1.1.1。
崩溃原因
这个错误是因为ComposeView调用setContent()时,无法从View树中找到ViewTreeLifecycleOwner。通常发生在以下场景:
- ItemView还未完全挂载到Activity/Fragment的View树时就调用了
setContent() - RecyclerView快速滑动导致ItemView被回收复用时,View树关联的LifecycleOwner暂时失效
解决方案
1. 在ViewHolder初始化时绑定LifecycleOwner
在ViewHolder的构造方法中,提前给ComposeView设置LifecycleOwner,避免在onBindViewHolder时才处理。可以通过ViewTree获取当前的LifecycleOwner:
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val composeView: ComposeView = itemView.findViewById(R.id.compose_view) init { // 从根View获取LifecycleOwner ViewTreeLifecycleOwner.get(itemView.rootView)?.let { lifecycleOwner -> composeView.setLifecycleOwner(lifecycleOwner) } } }
2. 延迟调用setContent确保View已挂载
在onBindViewHolder中,通过View.post()延迟执行setContent(),确保ItemView已经被添加到View树中:
override fun onBindViewHolder(holder: MyViewHolder, position: Int) { holder.composeView.post { holder.composeView.setContent { // 你的Compose UI内容 Text(text = "列表项 $position") } } }
3. 升级Compose版本
Compose 1.1.1存在部分混合View系统的兼容性问题,升级到1.2.0及以上版本可以修复此类问题。修改gradle依赖:
implementation 'androidx.compose.ui:ui:1.2.0' implementation 'androidx.compose.material:material:1.2.0' // 同步升级其他相关Compose依赖,比如ui-tooling等
4. 替换为Compose原生LazyColumn(推荐)
如果项目架构允许,直接使用Compose原生的LazyColumn实现列表,彻底避免View系统和Compose的混合兼容性问题:
LazyColumn { items(yourDataList) { item -> // 列表项Compose UI Text(text = item.title) } }
内容的提问来源于stack exchange,提问作者Arka Prava Basu
相关产品推荐
相关产品推荐

