简体   繁体   English

为什么Android Navigation Component 屏幕不返回上一个Fragment,而是调用了previos Fragment 的onViewCreated 中的一个方法?

[英]Why Android Navigation Component screen not go back to previous Fragment,but a method in onViewCreated of previos Fragment being called?

I have 2 fragment call CreateRoomFragment and DisplayPhotoFragment ,the navigation graph is look like this:我有 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>

So when I wanna to move from CreateRoomFragment to DisplayPhotoFragment ,I use the do as below:所以当我想从CreateRoomFragment移动到DisplayPhotoFragment ,我使用如下方法:

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

Doing this,I can navigate to DisplayPhotoFragment .这样做,我可以导航到DisplayPhotoFragment

But when I press back button of the device and also the Back arrow from the toolbar,it cant go back to CreateRoomFragment .但是,当我按back了装置的按钮,也Back arrow从工具栏,它不能回去CreateRoomFragment

I tried this ,but still unable to back to previous fragment:我试过这个,但仍然无法回到上一个片段:

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

Main Problem now:现在主要问题:

By using the code above,the screen didnt go back to previous Fragment( CreateRoomFragment ).It still stuck in DisplayPhotoFragment ,but at the same time,an API method in CreateRoomFragment onViewCreated section is being called.使用上面的代码,屏幕没有回到之前的Fragment( CreateRoomFragment )。它仍然卡在DisplayPhotoFragment ,但同时调用了CreateRoomFragment onViewCreated部分的API方法。

What causing this?这是什么原因造成的? and how can I solve this problem?我该如何解决这个问题?

I had the same problem.我有同样的问题。 For me the issue was that I was using a LiveData boolean to decide when to go to the next fragment.对我来说,问题是我使用 LiveData 布尔值来决定何时转到下一个片段。 When I then navigated back/up the boolean was still true so it would automatically navigate forward again.当我向后/向上导航时,布尔值仍然为真,因此它会再次自动向前导航。

Android maintains a back stack that contains the destinations you've visited. Android 维护一个返回堆栈,其中包含您访问过的目的地。 The first destination of your app is placed on the stack when the user opens the app.当用户打开应用程序时,应用程序的第一个目的地被放置在堆栈中。 Each call to the navigate() method puts another destination on top of the stack.每次调用navigate()方法都会将另一个目标放在堆栈顶部。 Tapping Up or Back calls the NavController.navigateUp() and NavController.popBackStack() methods, respectively, to remove (or pop) the top destination off of the stack. Tapping Up 或 Back 分别调用NavController.navigateUp()NavController.popBackStack()方法,以从堆栈中移除(或弹出)顶部目标。

NavController.popBackStack() returns a boolean indicating whether it successfully popped back to another destination. NavController.popBackStack()返回一个布尔值,指示它是否成功弹出回另一个目的地。 The most common case when this returns false is when you manually pop the start destination of your graph.返回 false 的最常见情况是您手动弹出图形的起始目的地。

When the method returns false, NavController.getCurrentDestination() returns null.当该方法返回 false 时, NavController.getCurrentDestination()返回 null。 You are responsible for either navigating to a new destination or handling the pop by calling finish() on your Activity.您负责导航到新目的地或通过在您的 Activity 上调用finish()来处理弹出窗口。

When navigating using an action, you can optionally pop additional destinations off of the back stack by using popUpTo and popUpToInclusive parameter of the action.使用操作进行导航时,您可以选择使用操作的popUpTopopUpToInclusive参数从返回堆栈中弹出其他目的地。

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

The best solution for handling navigation using live data is to use the SingleLiveEvent.使用实时数据处理导航的最佳解决方案是使用 SingleLiveEvent。

You can always use this class which is an extension of MutableLiveData.你总是可以使用这个类,它是 MutableLiveData 的扩展。

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

For a detail run down of this check:有关此检查的详细信息:

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

Had a similar issue.有一个类似的问题。 We still have multiple activities with nav component.我们仍然有多个带有导航组件的活动。 So imagine activity A -> activity B, activity B has its own nav and fragments.所以想象一下活动 A -> 活动 B,活动 B 有自己的导航和片段。 When the initial fragment tries to pop the back stack there is nowhere to pop back to and the nav controller does not know to finish the activity.当初始片段尝试弹出返回堆栈时,无处弹出,导航控制器不知道要完成活动。 So one solution I found was to do所以我找到的一个解决方案是做

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

If nav controller can not pop back it will finish activity.如果导航控制器无法弹出,它将完成活动。

You can use MutableSharedFlow instead on MutableLiveData if you want to observe the Event only once.如果您只想观察事件一次,则可以在MutableLiveData上使用MutableSharedFlow

in your viewModel :在您的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
    }

In your Activity/Fragment class:在您的Activity/Fragment类中:

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

viewModel.postEvent()

This will prevent observing data continuously when going back to fragment.这将防止在返回片段时连续观察数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM