Je montre une boîte de dialogue à l'intérieur d'un fragment en utilisant childFragmentManager
ou dans une activité en utilisant supportFragmentManager
, dans le processus, je voudrais définir le fragment cible, comme ceci:
val textSearchDialog = TextSearchDialogFragment.newInstance()
textSearchDialog.setTargetFragment(PlaceSearchFragment@this, 0)
Mais lors de l'exécution de ce code, j'obtiens l'erreur:
Java.lang.IllegalStateException: Fragment TextSearchDialogFragment {b7fce67 # 0 0} fragment cible déclaré PlaceSearchFragment {f87414 # 0 id = 0x7f080078} qui n'appartient pas à ce FragmentManager!
Je ne sais pas comment accéder au FragmentManager
que les composants de navigation utilisent pour gérer l'affichage du fragment, y a-t-il une solution?
Le modèle recommandé pour communiquer entre les fragments avec les composants de l'architecture de navigation est via un partagé ViewModel
- un ViewModel
qui vit au niveau d'activité atteint en récupérant le ViewModel
en utilisant ViewModelProviders.of(getActivity())
Selon la documentation , cela offre un certain nombre d'avantages:
- L'activité n'a rien à faire ni rien à savoir sur cette communication.
- Les fragments n'ont pas besoin de se connaître en plus du contrat
SharedViewModel
. Si l'un des fragments disparaît, l'autre continue de fonctionner comme d'habitude.- Chaque fragment a son propre cycle de vie et n'est pas affecté par le cycle de vie de l'autre. Si un fragment remplace l'autre, l'interface utilisateur continue de fonctionner sans aucun problème.
Pour développer la réponse acceptée:
(1) Créez un modèle de vue partagée qui serait utilisé pour partager des données entre les fragments de cette activité.
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Double> aDouble = new MutableLiveData<>();
public void setDouble(Double aDouble) {
this.aDouble.setValue(aDouble);
}
public LiveData<Double> getDouble() {
return aDouble;
}
}
(2) Stockez les données auxquelles vous souhaitez accéder dans le modèle de vue. Notez la portée du modèle de vue (getActivity).
SharedViewModel svm =ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
svm.setDouble(someDouble);
(3) Laissez le fragment implémenter l'interface de rappel de la boîte de dialogue et chargez la boîte de dialogue sans définir de fragment cible.
fragment.setOnDialogSubmitListener(this);
fragment.show(getActivity().getSupportFragmentManager(), TAG);
(4) Dans la boîte de dialogue, récupérez les données.
SharedViewModel svm =ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
svm.getDouble().observe(this, new Observer<Double>() {
@Override
public void onChanged(Double aDouble) {
// do what ever with aDouble
}
});
Avec viewmodel et fragment ktx, vous pouvez héberger un viewmodel partagé entre un fragment parent et un fragment enfant, donc au lieu d'avoir votre activité contenir l'instance du viewmodel et de stocker les données jusqu'à la fin de cette activité, vous pouvez stocker le viewmodel dans le parent fragment, ce faisant, lorsque vous ouvrez le fragment qui a instancié le viewmodel, le viewmodel sera effacé
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.2.1'
class ParentFragment:Fragment() {
private val model: SharedViewModel by viewModels()
}
class ChildFragment:Fragment(){
private val model: SharedViewModel by viewModels ({requireParentFragment()})
}
Ainsi, cela hébergera le modèle sharedviewmodel dans le fragment parent, et le fragment enfant dépendant de ce fragment parent aura accès à la même instance de SharedViewModel
et lorsque vous pop (aka détruire le fragment), votre onCleared()
La méthode se déclenchera sur votre viewmodel et ce shareviewmodel sera effacé, ainsi que toutes ses données.
De cette façon, vous n'avez pas votre MainActivity pour contenir toutes les données que les fragments partagent, et vous n'avez pas besoin d'effacer ces données chaque fois que vous quittez un fragment qui utilise le SharedViewModel
Maintenant en alpha, vous pouvez passer des données entre les navigations en utilisant également un modèle de vue qui enregistrera les données entre les navigations, disons que vous voulez partager des données entre le fragment B et le fragment A, maintenant vous pouvez le faire simplement avec deux lignes
https://developer.Android.com/guide/navigation/navigation-programmatic#returning_a_result