Jetpack Compose结合RecyclerView使用时报ComposeView未附着窗口错误
异常原因
java.lang.IllegalStateException: Cannot locate windowRecomposer; View androidx.compose.ui.platform.ComposeView{83fefc1 V.E...... ......I. 0,0-0,0} is not attached to a window
该异常的核心触发逻辑是:调用ComposeView.setContent()时,ComposeView尚未附着到当前页面的Window,默认的视图组合策略无法找到窗口关联的Recomposer完成Compose渲染初始化。
在RecyclerView搭配ComposeView的场景下,该异常通常出现在onCreateViewHolder阶段直接为新创建的ComposeView调用setContent的情况:此时ViewHolder还未完成绑定、也没有被添加到RecyclerView,自然没有关联到页面Window,因此触发报错。
修复方案
按优先级提供可落地的修复方案:
- 方案1(推荐):修改ComposeView的视图组合策略
Compose 1.2.0及以上版本提供了自定义组合策略的API,只需要在创建ComposeView后、调用setContent前,设置策略为DisposeOnViewTreeLifecycleDestroyed即可。该策略会自动绑定ComposeView所在父容器的生命周期,不需要等待窗口附着即可初始化渲染。
示例代码:
如果当前使用的Compose版本低于1.2.0,可以先升级Compose版本,或者使用下面的方案2。// 在Adapter的onCreateViewHolder中创建ComposeView时添加如下配置 val composeView = ComposeView(parent.context).apply { // 关键配置:修改组合策略 setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { // 自定义Composable布局代码 } } - 方案2:延迟setContent调用到View附着后
给ComposeView添加附着状态监听,等View成功attach到Window后再调用setContent:
示例代码:val composeView = ComposeView(parent.context) composeView.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View) { v.removeOnAttachStateChangeListener(this) (v as ComposeView).setContent { // 自定义Composable布局代码 } } override fun onViewDetachedFromWindow(v: View) = Unit }) - 方案3:调整setContent调用时机到onBindViewHolder
如果列表项内容需要随绑定数据动态变化,可以将setContent调用移到onBindViewHolder阶段,此时绝大多数场景下ViewHolder已经附着到RecyclerView,关联到了页面Window,也可以避免该报错。如果列表滑动速度极快存在小概率触发可能,推荐搭配方案1共同使用。
内容的提问来源于stack exchange,提问作者Dhaval
相关产品推荐
相关产品推荐

