问题
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.
回答1:
As per the Lifecycle.State.DESTROYED documentation:
After this event, this Lifecycle will not dispatch any more events.
I.e., DESTROYED
is a terminal state and once it is destroyed, that Lifecycle will always be destroyed.
This means there are two correct ways to do what you want:
Create a new Fragment instance each time you call
switchToA
orswitchToB
. Since all the state is destroyed when you remove a Fragment, you aren't gaining anything by reusing Fragment instances.Don't use
replace
, but instead useattach()
anddetach()
(i.e., attach the one you want to display, detach the one you want to hide). Fragments keep their state when detached (they aren't destroyed), so re-attaching it will move it back to resumed.
来源:https://stackoverflow.com/questions/53130047/fragment-not-receiving-livedata-updates-after-remove-add