使用 compose 在 AndroidView 中使用片段时崩溃

Posted

技术标签:

【中文标题】使用 compose 在 AndroidView 中使用片段时崩溃【英文标题】:Crash when using fragment in AndroidView using compose 【发布时间】:2022-01-06 03:30:37 【问题描述】:

我正在使用 compose 并尝试在 compose androidView 中包含一个片段。

所以在我的情况下,我们有一个带有 ComposeView 的 AFragment,在 ComposeView 中有一个 AndroidView,它创建一个 FragmentContainerView 并添加一个 PIFragment。

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View 
        return ComposeView(requireContext()).apply 
            setContent 
                AppTheme 
                    GalleryScreen(
                        factory = viewModelFactory,
                        remoteConfig = remoteConfig,
                        id = id,
                        currentPosition = currentPositionState,
                        onBack =  router.back(requireActivity()) ,
                    ) 
                        AndroidView(
                            modifier = Modifier
                                .fillMaxWidth()
                                .wrapContentHeight(),
                            factory = 
                                FragmentContainerView(context).apply 
                                    id = R.id.pFIC
                                
                            ,
                            update = 
                                childFragmentManager.beginTransaction().replace(
                                    R.id.pFIC,
                                    PIFragment::class.java,
                                    buildArguments(
                                        id = id,
                                        origin = origin,
                                    ), null
                                ).commitAllowingStateLoss()
                            ,
                        )
                    
                
            
        
    

一切正常,但是当我们在生产环境中发布此代码时,我们看到 firebase 崩溃了:

    java.lang.IllegalArgumentException: No view found for id 0x7f0b072b (...:id/pFIC) for fragment PIFragmentef1f89b (bdbe15f0-679d-41bb-8a27-367655f73545 id=0x7f0b072b)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:513)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
        at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1647)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3128)
        at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:3065)
        at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2988)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:546)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2180)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
        at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

【问题讨论】:

【参考方案1】:

事实上,崩溃是在重新创建父片段之后发生的。

在我的情况下是因为导航:

AFragment(带有 PIFragment) 导航到 BFragment 返回 A 片段

崩溃,因为片段管理器正在尝试重新创建 AFragment 和 PIFragment,但 compose pass 尚未完成,因此 pFIC 尚不存在。

解决方案是在父片段视图被销毁时移除 PIFragment。

    override fun onDestroyView() 
        childFragmentManager.findFragmentById(R.id.pFIC)?.let  fragment ->
            childFragmentManager.beginTransaction().remove(fragment).commitAllowingStateLoss()
        
        super.onDestroyView()
    

【讨论】:

以上是关于使用 compose 在 AndroidView 中使用片段时崩溃的主要内容,如果未能解决你的问题,请参考以下文章

Jetpack Compose 深入探索系列五:State Snapshot System

Android View体系自定义ViewGroup

Flutter 页面嵌入原生AndroidView.

Android View体系自定义View

Flutter 专题58 图解 Flutter 嵌入原生 AndroidView 小尝试 #yyds干货盘点#

Android View体系从源代码解析View的layout和draw流程