Résumé: Plusieurs LiveDataObserverssont déclenchés dans un fragment après avoir navigué vers un nouveau fragment, extrait le nouveau fragment et est retourné au fragment d'origine.
Détails: L'architecture est composée de MainActivityqui héberge un HomeFragmenten tant que destination de départ} dans le _ de MainActivity graphique de navigation. Dans HomeFragment est un programme gonflé PriceGraphFragment. Le HomeFragmentutilise le composant de navigation pour lancer un nouveau fragment enfant ProfileFragment. Au retour, le ProfileFragment est affiché et l'application revient au HomeFragment hébergeant le PriceGraphFragment. Le PriceGraphFragment est l'endroit où l'observateur est appelé plusieurs fois.
Je suis en train de consigner le hashcode de la table de hachage émise par Observer. Deux codes de hachage uniques sont alors affichés lorsque je vais au fragment de profil, saute le fragment de profil et retourne au fragment de prix. Ceci est opposé à l'un hashcode vu de la HashMap quand je tourne l'écran sans lancer le fragment de profil.
Composant de navigation pour lancer le nouveau ProfileFragment dans HomeFragment.
view.setOnClickListener(Navigation.createNavigateOnClickListener( R.id.action_homeFragment_to_profileFragment, null))
ViewModelcreation in Fragment (PriceGraphFragment). Le ViewModel a été enregistré et les données associées à plusieurs observateurs possèdent des données initialisées une seule fois dans ViewModel.
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) priceViewModel = ViewModelProviders.of(this).get(PriceDataViewModel::class.Java) }
Écoutez les données de ViewModeldans le fragment d'origine (PriceGraphFragment). Cet appel est appelé plusieurs fois. Toutefois, il ne devrait y avoir qu'un observateur lorsque le fragment est chargé.
priceViewModel.graphLiveData.observe( this, Observer { priceGraphDataMap: HashMap<Exchange, PriceGraphLiveData>? -> // This is being called multiple times. })
priceViewModel = ViewModelProviders.of(this).get(PriceDataViewModel::class.Java)
Création du ViewModel à l'aide de l'activité du fragment et du fragment parent du fragment enfant.priceViewModel = ViewModelProviders.of(activity!!).get(PriceDataViewModel::class.Java)
priceViewModel = ViewModelProviders.of(parentFragment!!).get(PriceDataViewModel::class.Java)
viewLifecycleOwner
au lieu de this
pour LifecycleOwnerdans la méthode observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
.ChildFragmentManager
et SupportFragmentManager
au niveau de l'activité).onViewCreated()
?ParentFragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
user = viewModel.getCurrentUser()
if (savedInstanceState == null) {
fragmentManager
?.beginTransaction()
?.replace(binding.priceDataContainer.id,
PriceGraphFragment.newInstance())
?.commit()
}
Tout d’abord, merci à tous ceux qui ont posté ici. C’est une combinaison de vos conseils et de vos conseils qui m’a aidé à résoudre ce problème au cours des 5 derniers jours, car de nombreux problèmes étaient en cause.
Avant:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
if (savedInstanceState == null) {
fragmentManager
?.beginTransaction()
?.add(binding.priceDataContainer.id, PriceGraphFragment.newInstance())
?.commit()
fragmentManager
?.beginTransaction()
?.add(binding.contentFeedContainer.id, ContentFeedFragment.newInstance())
?.commit()
}
...
}
Après:
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
if (savedInstanceState == null
&& childFragmentManager.findFragmentByTag(PRICEGRAPH_FRAGMENT_TAG) == null
&& childFragmentManager.findFragmentByTag(CONTENTFEED_FRAGMENT_TAG) == null) {
childFragmentManager.beginTransaction()
.replace(priceDataContainer.id, PriceGraphFragment.newInstance(),
PRICEGRAPH_FRAGMENT_TAG)
.commit()
childFragmentManager.beginTransaction()
.replace(contentFeedContainer.id, ContentFeedFragment.newInstance(),
CONTENTFEED_FRAGMENT_TAG)
.commit()
}
...
}
Création de ViewModel s dans onCreate()
par opposition à onCreateView()
pour les fragments parent et enfant.
Initialisation de la demande de données (requête Firebase Firestore) du fragment enfant (PriceFragment) dans onCreate()
plutôt que onViewCreated()
, mais ne le faisant que lorsque saveInstanceState est null .
Quelques éléments ont été suggérés mais n’ont pas eu d’impact sur la résolution de ce bug.
Création de Observers in onActivityCreated()
. Je garde le mien dans onViewCreated()
du fragment enfant (PriceFragment).
Utiliser viewLifecycleOwner
dans Observer creation. J'utilisais la variable this
de l'enfant Fragment (PriceFragment) auparavant. Même si viewLifecycleOwner
n’a pas d’impact sur ce bogue, il semble que ce soit une bonne pratique, donc je conserve cette nouvelle implémentation.
C’est un bug dans l’architecture. Vous pouvez en lire plus à ce sujet ici . Vous pouvez le résoudre en utilisant getViewLifecycleOwner au lieu de cela dans l'observateur. Comme ça:
mViewModel.methodToObserve().observe(getViewLifecycleOwner(), new Observer<Type>() {
@Override
public void onChanged(@Nullable Type variable) {
Et mettez ce code dans onActivityCreated (), car l'utilisation de getViewLifecycleOwner nécessite une vue.