当前位置: 首页 > 知识库问答 >
问题:

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

於德馨
2023-03-14

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

val textSearchDialog = TextSearchDialogFragment.newInstance()
textSearchDialog.setTargetFragment(PlaceSearchFragment@this, 0)

但在运行该代码时,我得到了一个错误:

java.lang.非法状态异常:片段文本搜索对话片段{b7fce67#0 0}声明不属于此FragmentManager的目标片段PlaceSearch片段{f87414#0 id=0x7f080078}!

共有3个答案

祁嘉言
2023-03-14

使用viewmodel和fragment ktx,您可以在父片段和子片段之间托管一个共享viewmodel,因此,您可以将viewmodel存储在父片段中,而不是让您的活动包含viewmodel的实例并存储数据,直到该活动完成,这样,当您弹出实例化viewmodel的片段时,viewmodel将被清除

implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
 implementation 'androidx.navigation:navigation-fragment-ktx:2.2.1'
class ParentFragment:Fragment() {
 private val model: SharedViewModel by viewModels()
}
class ChildFragment:Fragment(){
private val model: SharedViewModel by viewModels ({requireParentFragment()})
}

因此,这样做将在父片段中托管sharedviewmodel,并且依赖于该父片段的子片段将访问相同的sharedviewmodel实例,当您弹出(即销毁片段)时,您的onCleared()方法将在您的viewmodel中激发,该shareviewmodel以及它的所有数据都将被清除。

这样,您就没有您的Mainactive来包含片段共享的所有数据,并且您不需要在每次离开使用SharedViewModel的片段时清除该数据

现在在alpha中,您可以使用视图模型在导航之间传递数据,该视图模型将保存导航之间的数据,假设您想在片段B和片段A之间共享数据,现在您只需两行即可完成

https://developer.android.com/guide/navigation/navigation-programmatic#returning_a_result

田曜瑞
2023-03-14

详细说明公认的答案:

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

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

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

SharedViewModel svm =ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
svm.setDouble(someDouble);

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

fragment.setOnDialogSubmitListener(this);
fragment.show(getActivity().getSupportFragmentManager(), TAG);

(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
    }
}); 
诸葛煜
2023-03-14

更新:作为Navigation 2.3.0的一部分,Navigation添加了对返回结果的明确支持,其中有一个关于从对话框目标返回结果的特定部分,作为使用共享ViewModel的替代方法。

上一个答案:

在Fragments与导航架构组件之间进行通信的推荐模式是通过共享的ViewModel-一个ViewModel,它位于活动级别,通过使用ViewModelProvider(getActive())检索ViewModel来实现

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

  • 该活动不需要做任何事情,也不需要知道有关此通信的任何事情。
  • 除了SharedViewModel合约之外,片段不需要相互了解。如果其中一个片段消失,另一个会照常工作。
  • 每个片段都有自己的生命周期,不受另一个片段生命周期的影响。如果一个片段替换了另一个片段,UI会继续工作,没有任何问题。

通过使用导航图范围的ViewModel,您还可以在比整个活动更小的范围内共享ViewModels。

 类似资料:
  • 是否可以将新的导航架构组件与DialogFragment一起使用?我必须创建自定义导航器吗? 我很乐意将它们与导航图中的新功能结合使用。

  • 我想在新用户登录时设置用户名和图片。我已经尝试过使用findViewById(),但是当我设置值“navHeaderName.setText(user_name);”时它给了我空指针异常。

  • 我正在创建一个Android应用程序(Java),并第一次使用导航组件和Hilt。在导航编辑器中,我正在创建目标,并看到我创建的已用@AndroidEntryPoint注释的片段现在显示为“Hilt_”片段名称。现在我的应用程序无法构建,因为编译器正在寻找一个具有“Hilt_”片段名称而不仅仅是片段名称的构造函数。例如:我的片段名为Home片段,但在导航编辑器中它被称为Hilt_HomeFragm

  • 我正在我的应用程序中尝试导航架构组件。早些时候,我使用片段事务来实现以下功能。基本上,我想从导航。 碎片- 如果我正在使用导航组件并尝试 然后结果是FragmentA被FragmentB替换并且背景片段不可见。 我想知道一个解决方案,如果导航架构组件允许的话。 附言:我听说过嵌套导航主机,但从内部使用它好吗。 更新: FragmentB将有进一步交易的行动,例如: 碎片- 当用户按下后退按钮时,片

  • 到目前为止,我已经成功地导航到对话框并仅使用导航组件返回。问题是,我必须在对话框中做一些事情,并将结果返回到调用对话框的片段。 一种方法是使用共享viewmodel。但我必须使用。(活动)这让我的应用程序占用了一个单独的内存,即使我不再需要它。 另一种方法是覆盖show(framentManager, id)方法,访问片段管理器并从中访问先前的片段,然后将其设置为目标片段。我以前使用过目标片段方法

  • 我正在我的应用程序中使用导航组件。我试图在单击操作栏图标时导航到片段,但它不起作用。以下是我的代码: 操作菜单。xml nav_主机。xml 主要活动。Java语言 这种方法不起作用-我如何导航?