Android Fragments 为什么Android导航组件屏幕没有返回到上一个Fragment,而是调用了前一个Fragment的onViewCreated中的一个方法?

3b6akqbq  于 2023-10-19  发布在  Android
关注(0)|答案(6)|浏览(129)

我有两个片段调用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>

所以当我想从CreateRoomFragment移动到DisplayPhotoFragment时,我使用如下的do:

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

目前主要问题:

通过使用上面的代码,屏幕没有返回到以前的片段(CreateRoomFragment)。它仍然停留在DisplayPhotoFragment中,但同时,CreateRoomFragmentonViewCreated部分中的一个API方法被调用。
是什么造成的?我该怎么解决这个问题呢?

i5desfxk

i5desfxk1#

我也有同样的问题。对我来说,问题是我使用LiveData布尔值来决定何时进入下一个片段。当我导航返回/向上时,布尔值仍然为真,所以它会自动再次向前导航。

xesrikrc

xesrikrc2#

Android维护一个返回堆栈,其中包含您访问过的目的地。当用户打开应用时,应用的第一个目标将被放置在堆栈中。对navigate()方法的每次调用都将另一个目的地放在堆栈顶部。Tapping Up或Back分别调用NavController.navigateUp()NavController.popBackStack()方法,以从堆栈中移除(或弹出)顶部目标。
NavController.popBackStack()返回一个布尔值,指示它是否成功地弹出到另一个目的地。返回false的最常见情况是手动弹出图表的开始目标。
当方法返回false时,NavController.getCurrentDestination()返回null。您负责导航到新目的地或通过在Activity上调用finish()来处理弹出。
当使用操作导航时,您可以选择使用操作的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
    )
    ...
}
iqih9akk

iqih9akk3#

使用实时数据处理导航的最佳解决方案是使用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

b5buobof

b5buobof4#

也有类似的问题。我们仍然有多个活动与导航组件。想象一下活动A ->活动B,活动B有自己的导航和片段。当初始片段试图弹出返回堆栈时,没有地方可以弹出,并且nav控制器不知道要完成该活动。所以我找到的一个解决办法是

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

如果导航控制器不能弹出回来,它将完成活动。

cgfeq70w

cgfeq70w5#

如果你只想观察一次事件,你可以在MutableLiveData上使用MutableSharedFlow
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()

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

vaj7vani

vaj7vani6#

我有一个与你类似的问题:我决定利用导航抽屉中的HomeFragment浮动按钮来创建一个搜索按钮,所以我使用navController.navigate来转到导航抽屉中的另一个项目。好吧,它工作得很好,然而,用户无法返回到前一个项目.
我通过在导航到新的导航抽屉项之前添加navController.popBackStack()解决了这个问题。

val drawerLayout: DrawerLayout = binding.drawerLayout
val navView: NavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_content_main)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
appBarConfiguration = AppBarConfiguration(
    setOf(
        R.id.nav_home, R.id.nav_search
    ), drawerLayout
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
binding.appBarMain.fab.setOnClickListener { view ->
    navController.popBackStack()
    navController.navigate(R.id.nav_search)
}

相关问题