含ComposeView的Fragment配置MaterialSharedAxis返回时崩溃如何解决
问题现象
存在如下TimelineFragment实现:
class TimelineFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val axis = MaterialSharedAxis.Z val forward = MaterialSharedAxis(axis, true) val backward = MaterialSharedAxis(axis, false) enterTransition = forward exitTransition = forward reenterTransition = backward returnTransition = backward } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ) = ComposeView(requireActivity()).apply { setContent { Text(text = "Testing") } } }
从该Fragment点击返回按钮时应用崩溃,核心报错为:
java.lang.UnsupportedOperationException: Cannot add views to ComposeView; only Compose content is supported
完整崩溃堆栈:
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.farmersbyte.agripro, PID: 8524 java.lang.UnsupportedOperationException: Cannot add views to ComposeView; only Compose content is supported at androidx.compose.ui.platform.AbstractComposeView.checkAddView(ComposeView.android.kt:202) at androidx.compose.ui.platform.AbstractComposeView.addView(ComposeView.android.kt:346) at androidx.transition.TransitionUtils.createViewBitmap(TransitionUtils.java:138) at androidx.transition.TransitionUtils.copyViewImage(TransitionUtils.java:64) at androidx.transition.Visibility.onDisappear(Visibility.java:404) at androidx.transition.Visibility.createAnimator(Visibility.java:257) at androidx.transition.Transition.createAnimators(Transition.java:744) at androidx.transition.TransitionSet.createAnimators(TransitionSet.java:480) at androidx.transition.TransitionSet.createAnimators(TransitionSet.java:480) at androidx.transition.Transition.playTransition(Transition.java:1808) at androidx.transition.TransitionManager$MultiListener.onPreDraw(TransitionManager.java:300) at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:1088) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2745) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1721) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7598) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:966) at android.view.Choreographer.doCallbacks(Choreographer.java:790) at android.view.Choreographer.doFrame(Choreographer.java:725) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:951) at android.os.Handler.handleCallback(Handler.java:883) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7356) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
已知触发条件:
- 项目使用Jetpack Navigation组件实现Fragment导航
- 仅当Fragment设置了
MaterialSharedAxis转场动画、执行返回按压操作时触发崩溃 - Compose版本为1.0.1时无异常,升级到1.1.0及以上版本后出现该崩溃
崩溃原因
Compose 1.1.0及以上版本收紧了ComposeView的能力限制,直接禁止通过addView方法往ComposeView中添加View子节点,调用就会抛出UnsupportedOperationException。
而MaterialSharedAxis属于基于View系统实现的Visibility类转场,执行返回/退出动画的消失逻辑时,会调用TransitionUtils.copyViewImage方法,尝试在当前Fragment的根View上添加一个临时的视图快照节点来实现转场视觉效果。当Fragment直接返回ComposeView作为根节点时,这个addView操作就会直接触发崩溃。
原代码还存在两个不规范的点:
- 创建
ComposeView时传入了requireActivity()作为Context,应该使用LayoutInflater自带的上下文,避免主题不匹配、内存泄漏问题 - 没有给ComposeView设置合适的组合释放策略,容易引发Composition泄漏
修复方案
不要直接将ComposeView作为Fragment的根View返回,在外层套一层原生ViewGroup作为根容器,转场动画添加临时快照的操作会作用在这层原生容器上,不会触发ComposeView的限制。
修复后的代码示例:
override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ) = FrameLayout(inflater.context).apply { // 外层用原生FrameLayout作为根布局,承载转场逻辑 addView(ComposeView(context).apply { // 设置正确的Composition释放策略,绑定Fragment视图生命周期 setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { Text(text = "Testing") } }) }
该方案不需要修改转场动画逻辑,也不需要降级Compose版本,兼容所有1.1.0及以上版本的Compose。
内容的提问来源于stack exchange,提问作者Nabeel
相关产品推荐
相关产品推荐

