Fragment not receiving LiveData updates after remove + add

China☆狼群 提交于 2019-12-11 11:55:12

问题


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:

  1. Create a new Fragment instance each time you call switchToA or switchToB. Since all the state is destroyed when you remove a Fragment, you aren't gaining anything by reusing Fragment instances.

  2. Don't use replace, but instead use attach() and detach() (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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!