为什么Android Navigation Component screen 没有返回到上一个Fragment,而是调用了上一个Fragment 的onViewCreated 中的方法?
Why Android Navigation Component screen not go back to previous Fragment,but a method in onViewCreated of previos Fragment being called?
-
android
-
android-fragments
-
android-navigation
-
android-architecture-navigation
-
android-navigation-graph
我有 2 个片段调用 CreateRoomFragment
和 DisplayPhotoFragment
,导航图如下所示:
<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
时,我使用如下操作:
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
,但是同时,一个API的方法在 CreateRoomFragment
onViewCreated
节中被调用。
这是什么原因造成的?我该如何解决这个问题?
Android 维护一个包含您访问过的目的地的返回堆栈。当用户打开应用程序时,您的应用程序的第一个目的地被放置在堆栈上。每次调用 navigate()
方法都会将另一个目的地放在堆栈顶部。点击向上或向后分别调用 NavController.navigateUp()
和 NavController.popBackStack()
方法,以从堆栈中删除(或弹出)顶部目标。
NavController.popBackStack()
returns 一个布尔值,指示它是否成功弹出回另一个目的地。此 returns 错误的最常见情况是您手动弹出图形的起始目的地。
当方法returns为假时,NavController.getCurrentDestination()
returns为空。您负责导航到新目的地或通过在 Activity.
上调用 finish()
来处理弹出消息
使用操作导航时,您可以选择使用操作的 popUpTo
和 popUpToInclusive
参数从返回堆栈中弹出其他目的地。
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
)
...
}
我遇到了同样的问题。对我来说,问题是我使用 LiveData 布尔值来决定何时转到下一个片段。当我然后导航 back/up 时,布尔值仍然为真,因此它会自动再次向前导航。
使用实时数据处理导航的最佳解决方案是使用 SingleLiveEvent。
您可以随时使用此 class,它是 MutableLiveData 的扩展。
有关此检查的详细信息 运行:
https://proandroiddev.com/singleliveevent-to-help-you-work-with-livedata-and-events-5ac519989c70
有类似的问题。我们仍然有多个带有导航组件的活动。
所以想象一下 activity A -> activity B,activity B 有自己的导航和片段。当初始片段试图弹出返回堆栈时,无处可弹出,导航控制器不知道要完成 activity。所以我找到的一个解决方案是
if (!findNavController().popBackStack()) activity?.finish()
如果导航控制器无法弹出,它将完成 activity。
如果您只想观察一次事件,可以在 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
class:
lifecycleScope.launchWhenStarted {
viewModel.events.collect {
}
}
viewModel.postEvent()
这将防止在返回片段时继续观察数据。
android
android-fragments
android-navigation
android-architecture-navigation
android-navigation-graph
我有 2 个片段调用 CreateRoomFragment
和 DisplayPhotoFragment
,导航图如下所示:
<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
时,我使用如下操作:
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
,但是同时,一个API的方法在 CreateRoomFragment
onViewCreated
节中被调用。
这是什么原因造成的?我该如何解决这个问题?
Android 维护一个包含您访问过的目的地的返回堆栈。当用户打开应用程序时,您的应用程序的第一个目的地被放置在堆栈上。每次调用 navigate()
方法都会将另一个目的地放在堆栈顶部。点击向上或向后分别调用 NavController.navigateUp()
和 NavController.popBackStack()
方法,以从堆栈中删除(或弹出)顶部目标。
NavController.popBackStack()
returns 一个布尔值,指示它是否成功弹出回另一个目的地。此 returns 错误的最常见情况是您手动弹出图形的起始目的地。
当方法returns为假时,NavController.getCurrentDestination()
returns为空。您负责导航到新目的地或通过在 Activity.
finish()
来处理弹出消息
使用操作导航时,您可以选择使用操作的 popUpTo
和 popUpToInclusive
参数从返回堆栈中弹出其他目的地。
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
)
...
}
我遇到了同样的问题。对我来说,问题是我使用 LiveData 布尔值来决定何时转到下一个片段。当我然后导航 back/up 时,布尔值仍然为真,因此它会自动再次向前导航。
使用实时数据处理导航的最佳解决方案是使用 SingleLiveEvent。
您可以随时使用此 class,它是 MutableLiveData 的扩展。
有关此检查的详细信息 运行:
https://proandroiddev.com/singleliveevent-to-help-you-work-with-livedata-and-events-5ac519989c70
有类似的问题。我们仍然有多个带有导航组件的活动。 所以想象一下 activity A -> activity B,activity B 有自己的导航和片段。当初始片段试图弹出返回堆栈时,无处可弹出,导航控制器不知道要完成 activity。所以我找到的一个解决方案是
if (!findNavController().popBackStack()) activity?.finish()
如果导航控制器无法弹出,它将完成 activity。
如果您只想观察一次事件,可以在 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
class:
lifecycleScope.launchWhenStarted {
viewModel.events.collect {
}
}
viewModel.postEvent()
这将防止在返回片段时继续观察数据。