13

我有 2 个片段调用CreateRoomFragmentDisplayPhotoFragment导航图如下所示:

<navigation>    
<fragment
    android:id="@+id/createRoomFragment"
    android:name="package.room.CreateRoomFragment"
    android:label="Create a room"
    tools:layout="@layout/fragment_create_room">
    <action
        android:id="@+id/action_createRoomFragment_to_roomFragment"
        app:destination="@id/roomFragment" />
    <action
        android:id="@+id/action_createRoomFragment_to_displayPhotoFragment"
        app:destination="@id/displayPhotoFragment" />
</fragment>

<fragment
    android:id="@+id/displayPhotoFragment"
    android:name="package.fragment.DisplayPhotoFragment"
    android:label="fragment_display_photo"
    tools:layout="@layout/fragment_display_photo" >
    <argument android:name="bitmap"
              app:argType="android.graphics.Bitmap"/>
</fragment>

因此,当我想从 to 移动时CreateRoomFragmentDisplayPhotoFragment我使用如下操作:

NavDirections action = CreateRoomFragmentDirections.actionCreateRoomFragmentToDisplayPhotoFragment(selectedPhoto);
Navigation.findNavController(view).navigate(action);

这样做,我可以导航到DisplayPhotoFragment.

但是当我按下back设备的按钮以及Back arrow工具栏中的按钮时,它无法返回CreateRoomFragment

我试过这个,但仍然无法回到上一个片段:

requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(),
                new OnBackPressedCallback(true) {
                    @Override
                    public void handleOnBackPressed() {

                       navController.navigateUp();  //I tried this 
                       navController.popBackStack(R.id.createRoomFragment,false); //and also this
                    }
                });

现在主要问题:

通过使用上面的代码,屏幕没有回到之前的Fragment( CreateRoomFragment)。它仍然卡在DisplayPhotoFragment,但同时调用了CreateRoomFragment onViewCreatedsection中的API方法。

这是什么原因造成的?我该如何解决这个问题?

4

5 回答 5

24

我有同样的问题。对我来说,问题是我使用 LiveData 布尔值来决定何时转到下一个片段。然后当我向后/向上导航时,布尔值仍然为真,因此它会再次自动向前导航。

于 2020-02-27T08:29:46.573 回答
18

Android 维护一个包含您访问过的目的地的后台堆栈。当用户打开应用程序时,应用程序的第一个目的地被放置在堆栈中。对该方法的每次调用都会navigate()在堆栈顶部放置另一个目标。Tapping Up 或 Back 分别调用NavController.navigateUp()NavController.popBackStack()方法,以从堆栈中移除(或弹出)顶部目标。

NavController.popBackStack()返回一个布尔值,指示它是否成功弹回另一个目的地。返回 false 的最常见情况是您手动弹出图形的起始目标。

当方法返回 false 时,NavController.getCurrentDestination()返回 null。您负责导航到新目的地或通过调用finish()您的活动来处理弹出窗口。

使用操作进行导航时,您可以选择使用操作的popUpToandpopUpToInclusive参数将其他目的地从后台堆栈中弹出。

class MyFragment : Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val onBackPressedCallback = object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                if (true == conditionForCustomAction) {
                    CustomActionHere()
                } else  NavHostFragment.findNavController(this@MyFragment).navigateUp();    
        }
    }
    requireActivity().onBackPressedDispatcher.addCallback(
        this, onBackPressedCallback
    )
    ...
}
于 2020-01-31T11:40:25.903 回答
2

使用实时数据处理导航的最佳解决方案是使用 SingleLiveEvent。

您始终可以使用此类,它是 MutableLiveData 的扩展。

https://gist.githubusercontent.com/cdmunoz/ebe5c4104dadc2a461f512ea1ca71495/raw/a17f76754f86a4c0b1a6b43f5c6e6d179535e627/SingleLiveEvent.kt

有关此检查的详细信息:

https://proandroiddev.com/singleliveevent-to-help-you-work-with-livedata-and-events-5ac519989c70

于 2021-02-09T00:07:16.330 回答
1

有类似的问题。我们仍然有多个带有导航组件的活动。所以想象活动 A -> 活动 B,活动 B 有自己的导航和片段。当初始片段尝试弹回堆栈时,无处可弹回并且导航控制器不知道完成活动。所以我发现的一个解决方案是

if (!findNavController().popBackStack()) activity?.finish()

如果导航控制器无法弹回,它将完成活动。

于 2021-05-25T18:52:08.210 回答
0

如果您只想观察事件一次,则可以使用MutableSharedFlowon 。MutableLiveData

在你的viewModel

 private val _events = MutableSharedFlow<Event>()
    val events = _events.asSharedFlow() // read-only public view

    suspend fun postEvent() {
        _events.emit(event) // suspends until subscribers receive it
    }

在你的Activity/Fragment课堂上:

lifecycleScope.launchWhenStarted {
   viewModel.events.collect {
   }
}

viewModel.postEvent()

这将防止在返回片段时连续观察数据。

于 2022-01-06T18:50:40.550 回答