使用NavigationComponent,在观察另一个DialogFragment的结果后,在navBackStackEntry中显示DialogFragment。

3

以下是我的Fragment的onViewCreated方法:

@Override
public void onViewCreated(@NonNull View view, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    NavHostFragment navHostFragment = (NavHostFragment) requireActivity().getSupportFragmentManager().findFragmentById(R.id.container);

    binding.button.setOnClickListener(v -> {
        if (navHostFragment != null) {
            NavController navController0 = navHostFragment.getNavController();

            navController0.navigate(MyFragmentDirections.actionMyFragmentToMessageDialog(
                    false,
                    R.drawable.ic_success,
                    "My Message 1",
                    R.string.yes,
                    R.string.no,
                    R.drawable.circle_yellow
            ));
        }
    });

    if (navHostFragment != null) {
        NavController navController1 = navHostFragment.getNavController();
        NavBackStackEntry navBackStackEntry = navController1.getCurrentBackStackEntry();
        if (navBackStackEntry != null) {
            SavedStateHandle savedStateHandle = navBackStackEntry.getSavedStateHandle();
            MutableLiveData<String> liveData = savedStateHandle.getLiveData(Const.DIALOG_BTN_DATA);
            liveData.observe(getViewLifecycleOwner(), btnData -> {
                //            savedStateHandle.remove(Const.DIALOG_BTN_DATA);

                if (btnData.equals("btn_right")) {
                    Log.i(TAG, "Dialog Btn Clicked -----> btn_right");
                    NavController navController2 = navHostFragment.getNavController();
                    navController2.navigate(MyFragmentDirections.actionMyFragmentToMessageDialog(
                            false,
                            R.drawable.ic_success,
                            "My Message 2",
                            R.string.yes,
                            R.string.no,
                            R.drawable.circle_red
                    ));

                } else {
                    // Do Some Stuff
                }
            });
        }
    }
}

这是对话框的 onClickListener 按钮:

binding.btnRight.setOnClickListener(v -> {
    NavHostFragment navHostFragment = (NavHostFragment) requireActivity().getSupportFragmentManager().findFragmentById(R.id.container);
    if (navHostFragment != null) {
        NavController navController = navHostFragment.getNavController();
        NavBackStackEntry navBackStackEntry = navController.getPreviousBackStackEntry();
        if (navBackStackEntry != null) {
            SavedStateHandle savedStateHandle = navBackStackEntry.getSavedStateHandle();
            savedStateHandle.set(Const.DIALOG_BTN_DATA, "btn_right");
        }
        navController.navigateUp();
    }
});

我需要在接收到另一个DialogFragment的结果时显示DialogFragment,但是在语句navController2.navigate(MyFragmentDirections.actionMyFragmentToMessageDialog...中应用程序崩溃,并出现以下错误:

java.lang.IllegalArgumentException: Navigation action/destination com.example.app:id/action_myFragment_to_messageDialog cannot be found from the current destination

有人可以帮我解决这个问题吗?我需要在使用NavigationComponent时,在navBackStackEntry观察器中展示另一个DialogFragment的结果,并显示DialogFragment。


你读了使用对话框目标时需要考虑的事项吗?它详细地解释了这种情况下发生的事情以及适用于此情况的代码。你没有遵循该指南的原因是什么呢? - ianhanniballake
1个回答

1
您的问题与navController的使用无关。您可以在Navigation Component文档中找到其定义。
因此,我避免描述它们并想专注于您的代码。 Action X to Y表示您只想从X导航到Y。换句话说,后退堆栈中的最后一个条目/目标必须是X

1.

在您的情况下,当显示MyFragment时,后退堆栈如下:

[ MyFragment ]

当你调用getSavedStateHandle()并开始观察其savedState时,意味着你正在观察MyFragment的savedState。

2.

当你想在按钮单击监听器中启动带有"My Message 1"的对话框时,返回栈仍然是:

[ MyFragment ]

启动后,对话框将会是这样的:
[ MyFragment, MessageDialog ]

所以,当你在对话框中使用getPreviousBackStackEntry时,它指的是MyFragment,并成功地在MyFragment的savedState上设置了set(Const.DIALOG_BTN_DATA, "btn_right")
此时,MyFragment中的观察者将被触发,并尝试通过actionMyFragmentToMessageDialog启动带有"My Message 2"的对话框。
这个操作是从MyFragmentMessageDialog的,但后退栈中的最新条目是MessageDialog(而不是MyFragment)。BOOOM navController.navigateUp()将永远不会调用弹出对话框:D。

如何使用NavigationComponent在观察另一个DialogFragment的navBackStackEntry结果时显示DialogFragment?

您的问题源于本地操作的限制。因此,您应该通过destination-iddeeplink进行导航,或者更好的方法是使用提供安全参数功能的GlobalActions

我建议在这种情况下使用全局操作:

<action
    android:id="@+id/action_global_messageDialog"
    app:destination="@id/messageDialog" />

navController2.navigate(
    MyGraphDirections.actionGlobalMessageDialog(
        false,
        R.drawable.ic_success,
        "My Message 2"
        R.string.yes,
        R.string.no,
        R.drawable.circle_red
    ));

感谢您提供如此详细的解释。那么该如何解决呢? - Alireza Noorali
@AlirezaNoorali,你刚才提到了一个崩溃问题,但没有写出你的需求。请更新问题,我会再次检查。 - beigirad
@AlirezaNoorali 我的回答已经更新了。 - beigirad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接