Crash when using fragment in AndroidView using compose

I’m playing around with compose and tried to include a fragment inside a compose AndroidView.

So in my situation, we have AFragment with a ComposeView and inside the ComposeView there is an AndroidView which create a FragmentContainerView and add a 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()
                            },
                        )
                    }
                }
            }
        }
    }

All was working fine, but when we publish this code in production, we saw crash in firebase:

    java.lang.IllegalArgumentException: No view found for id 0x7f0b072b (...:id/pFIC) for fragment PIFragment{ef1f89b} (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)

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

In fact, the crash was happening after the parent fragment was recreated.

In my case because of navigation:

  • AFragment (with PIFragment)
  • navigate to BFragment
  • back to AFragment

Crash, because the fragment manager is trying to recreate AFragment and PIFragment, but the compose pass is not done so pFIC does not exist yet.

The solution was to remove the PIFragment when the parent fragment view is destroyed.

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

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply