如何在使用导航组件时设置对话框的目标片段

Eur*_*tré 10 android kotlin android-navigation android-architecture-components android-architecture-navigation

我在一个片段里面使用childFragmentManager或在一个Activity 里面显示一个对话框supportFragmentManager,在这个过程中我想设置目标片段,如下所示:

val textSearchDialog = TextSearchDialogFragment.newInstance()
textSearchDialog.setTargetFragment(PlaceSearchFragment@this, 0)
Run Code Online (Sandbox Code Playgroud)

但是当运行该代码时,我得到错误:

java.lang.IllegalStateException:Fragment TextSearchDialogFragment {b7fce67#0 0}声明的目标片段PlaceSearchFragment {f87414#0 id = 0x7f080078}不属于此FragmentManager!

我不知道如何访问FragmentManager导航组件正在使用来管理片段的显示,有没有解决方案呢?

ian*_*ake 10

片段与导航架构组件之间进行通信的推荐模式是通过共享ViewModel - ViewModel通过检索ViewModel使用来实现活动级别的共享ViewModelProviders.of(getActivity())

根据文档,这提供了许多好处:

  • 活动不需要做任何事情,也不需要了解这种沟通.
  • SharedViewModel合同外,碎片不需要彼此了解.如果其中一个碎片消失,另一个碎片继续照常工作.
  • 每个片段都有自己的生命周期,不受另一个片段的生命周期的影响.如果一个片段替换另一个片段,则UI继续工作而没有任何问题.

  • @jskierbi-当然,这个问题有很多问题-您的目标片段未启动*因此,在那里进行任何操作都是不安全的,您已经将两个片段紧密耦合在一起,并且不得不使用Intent (以及可包裹对象),实际上任何对象都可以。当然,它并不是完美的,所以建议您为[navigateForResult()]本机类型的API [星标](https://issuetracker.google.com/issues/79672220)加上星号。 (3认同)
  • 我认为这是一个错误的答案。您绝不会想创建一个共享ViewModel来与您的对话框进行通信,该ViewModel在父Activity的整个生命周期中都有效。实际上,导航框架缺少添加目标片段的功能。 (2认同)
  • 如果Google推荐,共享ViewModel听起来不正确。它看起来类似于通过全局变量从函数返回值。当导航到详细信息/编辑片段时,我使用`newFragment.setTargetFragment(this)`实现了预期的流程,然后在返回之前调用`getTargetFragment()。onActivityResult(result,getTargetRequestCode())`(例如fragmentManger.popBackstack( ))。好处之一是,Android可以自动处理其中一个片段不存在的情况。我还没有找到用Navigation Component实现这种流程的方法。 (2认同)

Jef*_*rey 6

详细说明已接受的答案:

(1) 创建一个共享视图模型,用于在该 Activity 内的片段之间共享数据。

public class SharedViewModel extends ViewModel {

    private final MutableLiveData<Double> aDouble = new MutableLiveData<>();

    public void setDouble(Double aDouble) {
        this.aDouble.setValue(aDouble);
    }

    public LiveData<Double> getDouble() {
        return aDouble;
    }
}
Run Code Online (Sandbox Code Playgroud)

(2) 在视图模型中存储您要访问的数据。请注意视图模型 (getActivity) 的范围。

SharedViewModel svm =ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
svm.setDouble(someDouble);
Run Code Online (Sandbox Code Playgroud)

(3)让fragment实现对话框的回调接口,在不设置目标fragment的情况下加载对话框。

fragment.setOnDialogSubmitListener(this);
fragment.show(getActivity().getSupportFragmentManager(), TAG);
Run Code Online (Sandbox Code Playgroud)

(4) 在对话框内检索数据。

SharedViewModel svm =ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
svm.getDouble().observe(this, new Observer<Double>() {
    @Override
    public void onChanged(Double aDouble) {
        // do what ever with aDouble
    }
}); 
Run Code Online (Sandbox Code Playgroud)