I am currently playing around to get a hang of the fragment's lifecycle in relation to ViewModel and LiveData.
I have 2 fragments, fragmentA and fragmentB.
I add the Observer in the onCreate method of each fragment.
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sharedViewModel = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
sharedViewModel.getText().observe(this, new Observer<CharSequence>() {
@Override
public void onChanged(CharSequence charSequence) {
editText.setText(charSequence);
}
});
}
Each fragment has a button that changes LiveData in the shared ViewModel
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
[...]
buttonOk.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sharedViewModel.setText(editText.getText());
}
});
[...]
}
SharedViewModel:
public class SharedViewModel extends ViewModel {
private MutableLiveData<CharSequence> text = new MutableLiveData<>();
public void setText(CharSequence input) {
text.setValue(input);
}
public LiveData<CharSequence> getText() {
return text;
}
}
When I click a button, I replace the fragment for the other one.
public class MainActivity extends AppCompatActivity {
Fragment fragmentA = new FragmentA();
Fragment fragmentB = new FragmentB();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container_a, fragmentA)
.commit();
}
}
public void switchToA(View v) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, fragmentA)
.commit();
}
public void switchToB(View v) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, fragmentB)
.commit();
}
}
Replace causes the fragment to be fully destroyed and run through it's onCreate method again the next time it is added. I can confirm that onCreate is called for each fragment placed onto the screen and the Observer is added.
But once I replaced a fragment and re-added it, it completely stops getting any updates in onChanged. Even the ones it sent itself. onChanged is just not triggered anymore. I don't understand why.
Edit:
I actually found out that the followig if check in the LiveData class returns the 2nd time I try to add the Observer (after replacing the fragment for the first one):
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
Hence, the Observer is not added anymore. Why does getCurrentState() return DESTROYED when I try to re-add the fragment?
In short: the Observer is removed when the fragment is removed, but it doesn't add another Observer the next time the fragment is added.