Je travaille avec des composants d'architecture Android. Ce que je veux, c’est lorsque l’utilisateur tape "0" dans Edittext et clique sur le bouton pour remplacer Fragment par un nouveau, et si vous tapez autre chose un message d’erreur post Toast. Dans Problème, c’est quand je reviens d’un nouveau fragment (BlankFragment) et que je clique à nouveau sur le bouton et qu’on tape à nouveau "0" et qu’on clique sur onchange () est appelé plusieurs fois pour que le fragment soit créé plusieurs fois.
FragmentExample.class:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
manager = getActivity().getSupportFragmentManager();
viewmModel = ViewModelProviders.of(getActivity(), viewModelFactory)
.get(VModel.class);
View v = inflater.inflate(R.layout.fragment_list, container, false);
b = (Button) v.findViewById(R.id.b);
et = (EditText) v.findViewById(R.id.et);
viewmModel.observeData().observe(getActivity(), new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
if(s.equals("0")) {
BlankFragment fragment = (BlankFragment) manager.findFragmentByTag(DETAIL_FRAG);
if (fragment == null) {
fragment = BlankFragment.newInstance();
}
addFragmentToActivity(manager,
fragment,
R.id.root_activity_detail,
DETAIL_FRAG
);
} else {
Toast.makeText(getContext(), "Wrong text", Toast.LENGTH_SHORT).show();
}
}
});
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
viewmModel.setData(et.getText().toString());
}
});
return v;
}
private void addFragmentToActivity(FragmentManager fragmentManager, BlankFragment fragment, int root_activity_detail, String detailFrag) {
Android.support.v4.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(root_activity_detail, fragment, detailFrag).addToBackStack(detailFrag);
transaction.commit();
}
Classe de ré-histoire:
public class Repository {
MutableLiveData<String> dataLive = new MutableLiveData<>();
public Repository() {
}
public void setListData(String data) {
dataLive.setValue(data);
}
public MutableLiveData<String> getData() {
return dataLive;
}
}
BlankFragment.class:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
listItemViewModel = ViewModelProviders.of(this, viewModelFactory)
.get(VModel.class);
listItemViewModel.setData("");
return inflater.inflate(R.layout.fragment_blank, container, false);
}
Le problème ici est que lorsque vous séparez le fragment de l'activité, le fragment et son modèle de vue ne sont pas détruits. Lorsque vous revenez, vous ajoutez un nouvel observateur à la livedata
lorsque l'ancien observateur est toujours présent dans le même fragment (Si vous ajoutez l'observateur dans onCreateView()
. Il y a un article (même un fil SO en fait) en parle (avec la solution).
Le moyen le plus simple de résoudre ce problème (également dans l'article) consiste à supprimer tout observateur des données vivantes avant d'y ajouter l'observateur.
Mise à jour: dans la bibliothèque de support v28, un nouveau LifeCycleOwner appelé ViewLifeCycleOwner devrait corriger cela plus d’informations dans ici
Au lieu d'utiliser getActivity
en tant que LifecycleOwner, vous devez utiliser fragment.
Changement
viewmModel.observeData().observe(getActivity(), new Observer<String>() {
à
viewmModel.observeData().removeObservers(this);
viewmModel.observeData().observe(this, new Observer<String>() {
Vous ne devez pas créer votre viewmModel
dans onCreateView
, mais plutôt dans onCreate
afin de ne pas ajouter d'écouteur à vos données chaque fois que la vue est créée.
viewmModel = ViewModelProviders.of(getActivity(), viewModelFactory)
.get(VModel.class);
Comme votre viewmModel
's LifecycleOwner
est une activité, l'observateur ne sera automatiquement supprimé que lorsque l'état du cycle de vie est Lifecycle.State.DESTROYED .
Dans votre cas, l'observateur ne sera pas automatiquement supprimé. Vous devez donc supprimer manuellement l'observateur précédent ou transmettre la même instance d'observateur à chaque fois.