Hey all, I’m running into an issue with `AndroidVi...
# compose
j
Hey all, I’m running into an issue with
AndroidViewBinding
when hosting different fragments across two screens, hopefully someone here will be able to help me. In Screen A, I host
FragmentA
, and in Screen B, I host
FragmentB
, both are instances of the same fragment class. Even though I use the same composable function, each one is hosted in a different
FragmentContainerView
(I handle this by passing a
bindingFactory
lambda to
AndroidViewBinding
). When navigating from Screen A → Screen B, everything works fine:
FragmentManager
properly removes
FragmentA
before showing
FragmentB
. However, when navigating back from Screen B → Screen A, their lifecycles seem to overlap: `AndroidViewBinding`’s
onRelease
from Screen B is called after the
factory
from Screen A. This ends up replacing
FragmentA
with
FragmentB
on Screen A 🧵
When navigating from Screen B → Screen A,
FragmentB
isn’t removed in time, so for a moment the
FragmentManager
holds both fragments, and for some reason it gets confused and removes
FragmentA
instead of
FragmentB
.
I copied the
AndroidViewBinding
code to customize the
onRelease
logic, but even after adding a check to prevent the fragment removal when
fragmentManager.fragmentCount > 1
,
FragmentA
still gets removed.
Is there any way I can improve my setup to prevent this issue from happening?
i
You should not ever be using
AndroidViewBinding
for fragments anymore - use
AndroidFragment
which was built specifically because of these unsolvable problems with
AndroidViewBinding
j
I had seen
AndroidFragment
before, but I didn’t see a way to use it when having an existing instance of the fragment, which is what my current setup requires because I get the fragment instance from an SDK. Is there a way to use it like that?
i
AndroidFragment
uses the
FragmentFactory
you've set on your FragmentManager to create instances of your Fragment since that is what is going to unconditionally be used after you go through a config change / process death+recreation anyways
which means that either the SDK you are using is already just providing a default instance with a no-arg constructor and a Bundle of arguments (which you can extract from the Fragment via
fragment.arguments
and set those on
AndroidFragment
) or they're already not handling config changes correctly in the first place
j
That is indeed the case, I just needed to grab the arguments from the existing fragment instance and pass them to
AndroidFragment
. Interestingly, the problem still happens:
FragmentA
is replaced by
FragmentB
, but only the first time I navigate from Screen B → Screen A. After that, if I reset the state on Screen A so that
FragmentA
is shown again, it no longer occurs. I’m using the Navigation Component, and both screens are separate destinations in a bottom nav bar, could that be related?
i
Mmm, I don't see how that is possible given that the state of Screen B and Screen A are independent from one another (they have their own remembered values, etc.). What happens if you log the
currentCompositeKeyHash
right before each
AndroidFragment
call? Do you get different values or the same?
j
I get different values on each screen.
i
Then
AndroidFragment
is putting the fragments in different containers and there isn't any overlap between them
j
yes, I think the underlying issue is the same as with
AndroidViewBinding
, when `AndroidFragment`’s
onDispose
is invoked the
FragmentManager
is removing
FragmentA
instead of
FragmentB
, even though they’re hosted by different containers
Not even forcing a
AndroidFragment
recomposition on Screen A seem to prevent that from happening.
i
Fragments in separate containers are completely separate from one another
AndroidFragment
only looks up fragments by the container, which you said was different, so I'm not seeing how one could affect the other
If you can reproduce it in a minimal sample project, it would be worth filing a bug against Fragments: https://issuetracker.google.com/issues/new?component=460964&template=1182267
👍 1
j
will do, thanks for the help.