删除+添加后,片段未收到LiveData更新 [英] Fragment not receiving LiveData updates after remove + add

查看:397
本文介绍了删除+添加后,片段未收到LiveData更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在四处寻找与ViewModelLiveData相关的fragment生命周期.

I am currently playing around to get a hang of the fragment's lifecycle in relation to ViewModel and LiveData.

我有2个fragmentsfragmentAfragmentB. 我在每个fragmentonCreate方法中添加Observer.

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);
        }
    });
}

每个fragment都有一个按钮,用于更改共享ViewModel

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;
    }
}

当我单击一个按钮时,我将fragment替换为另一个.

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导致fragment被完全销毁,并在下一次添加时再次通过它的onCreate方法运行.我可以确认在屏幕上放置的每个fragment都调用了onCreate,并且添加了Observer. 但是,一旦我替换了fragment并重新添加了它,它便完全停止了onChanged中的任何更新.甚至它自己发送的那些. onChanged不再被触发.我不明白为什么.

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.

我实际上发现LiveData类中的followig if检查返回了第二次,我尝试添加Observer(在将fragment替换为第一个之后) ):

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;
    }

因此,不再添加Observer.当我尝试重新添加fragment时,为什么getCurrentState()返回DESTROYED?

Hence, the Observer is not added anymore. Why does getCurrentState() return DESTROYED when I try to re-add the fragment?

简而言之:删除fragment时会删除Observer,但是下次添加该片段时不会再添加另一个Observer.

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.

推荐答案

根据 Lifecycle.State.DESTROYED文档:

此事件之后,此生命周期将不再调度任何事件.

After this event, this Lifecycle will not dispatch any more events.

DESTROYED是终端状态,一旦销毁,生命周期将始终被销毁.

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:

    每次调用switchToAswitchToB时,
  1. 创建一个新的Fragment实例.由于删除Fragment时所有状态都被破坏,因此通过重用Fragment实例不会获得任何收益.

  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.

不要使用replace,而要使用attach()detach()(即,附加要显示的内容,分离要隐藏的内容).碎片在分离时仍保持其状态(不会被破坏),因此重新附加碎片会将其移回恢复状态.

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.

这篇关于删除+添加后,片段未收到LiveData更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆