添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

导航架构组件 - OnBackPressed() - Android

1 人关注

我在安卓导航架构的碎片中取得了进展。

当我在最后一个屏幕上按下按键时,或者当我在屏幕上放了一个按键并将按键功能设置为

val navıgattor = activity.findNavController(R.id.nav_host_fragment)
navigator.popBackStack()

并点击,我回到前一个片段,但前一个片段的onCreateView()方法又被调用。我希望它能在正常行为中保持状态。

我哪里做错了?

android
kotlin
android-jetpack
navigation-architecture
Mehmet Ceylan
Mehmet Ceylan
发布于 2020-08-10
3 个回答
Nikhil Sharma
Nikhil Sharma
发布于 2020-08-10
已采纳
0 人赞同

我将分为两部分回答 -

Solution:

不要在每次回到前一个片段时都膨胀视图。将视图保存在一个局部变量中,只膨胀一次。建议由 Ian Lake here

private var savedViewInstance: View? = null
override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
): View? {
    return if (savedViewInstance != null) {
        savedViewInstance
    } else {
        savedViewInstance =
                inflater.inflate(R.layout.fragment_professional_details, container, false)
        savedViewInstance

你得到的行为是默认行为,片段将在你每次调用navigator.popBackStack()或使用设备上的返回按钮时重新创建它们的视图。

让我们来理解导航架构下的片段的生命周期。

情景。我们有两个片段,HomeFragment和DashboardFragment。这两个片段都属于同一个NavGraph,并且起始目标是Home Fragment。

启动应用程序时的片段生命周期

HomeFragment: onAttach:

HomeFragment: onCreate:

HomeFragment: onCreateView:

HomeFragment: onViewCreated:

HomeFragment: onActivityCreated:

HomeFragment: onStart:

HomeFragment: onResume:

On Navigation: Home Fragment ---> Dashboard Fragment

DashboardFragment: onAttach:

DashboardFragment: onCreate:

DashboardFragment: onCreateView:

DashboardFragment: onViewCreated:

DashboardFragment: onActivityCreated:

DashboardFragment: onStart:

DashboardFragment: onResume:

HomeFragment: onPause:

HomeFragment: onStop:

HomeFragment: onDestroyView:

On Navigation: Dashboard Fragment ---> Home Fragment

HomeFragment: onAttach:

HomeFragment: onCreate:

HomeFragment: onCreateView:

HomeFragment: onViewCreated:

HomeFragment: onActivityCreated:

HomeFragment: onStart:

HomeFragment: onResume:

DashboardFragment: onPause:

DashboardFragment: onStop:

HomeFragment: onDestroy:

DashboardFragment: onDestroyView:

DashboardFragment: onDestroy:

如果我们在最初的HomeFragment: onCreateView()上保存视图,并在下一次调用HomeFragment: onCreateView()时每次充气相同的视图,我们可以得到旧的视图。

如果你注意到HomeFragment: onDestroy()将被调用,但是在HomeFragment: onViewCreated()被调用之后。调用HomeFragment: onDestroy()只是破坏了HomeFragment的旧实例。

我仍然认为这种做事方式不是最好的做法,但它将是直到,谷歌将出现类似onFragemntRestore()的东西。

另一方面,碎片应该在每次被移除或替换时被重新创建,你应该使用onSaveInstanceState()来恢复它们的状态。

在这里,ViewModel可以省去保存片段状态和恢复它们的麻烦。 要实际更新视图,你必须需要ViewModel并观察视图中的变化。

简单地说,如果你有something,无论你在哪里,它都会为你的观点提供数据,如果你回到同一个位置,没有任何变化,那something就有你之前的样子的信息。这个something就是ViewModel。

关于同一主题,还有许多其他值得阅读的内容,如this, this和this

编码愉快 !

Kristijan Zrno
Kristijan Zrno
发布于 2020-08-10
0 人赞同

你没有做错什么,这种行为对片段来说是正常的。当你导航到另一个片段时,片段管理器只保存事务而不保存当前片段的状态。

为了保存一个片段的实例状态,你可以覆盖 onSaveInstanceState() 函数并将数据放在out-state bundle中。 要取回保存的数据,你可以覆盖 onActivityCreated() 并检查数据是否包含在savedInstanceState包中。

你可以在这里查看片段的生命周期。

navid
navid
发布于 2020-08-10
0 人赞同

来自片段文件。

* Called when the view previously created by {@link #onCreateView} has * been detached from the fragment. The next time the fragment needs * to be displayed, a new view will be created. This is called * after {@link #onStop()} and before {@link #onDestroy()}. It is called * <em>regardless</em> of whether {@link #onCreateView} returned a * non-null view. Internally it is called after the view's state has * been saved but before it has been removed from its parent. public void onDestroyView()

所以每当onDestroyView被调用时(无论什么原因),你会看到onCreateView在片段回到顶部时被调用。为了恢复视图的状态,有一些工具可以考虑(你决定哪一个或哪一个混合工具适合你)。

1- 重写onSaveInstanceState,将当前状态作为bundle传递,并在android系统以bundle为参数调用onCreateView时重用它。

2- 使用一个 ViewModel 包含视图状态信息,它与片段、其视图或其父级活动结合在一起,并与之一起被销毁。

3- 在片段中保留一个由onCreateView返回的View对象的副本,如果在再次调用onCreateView时不为空,则重新使用(谨慎使用,因为有些视图可能会发现重绘的问题,例如 OSM地图视图 ):

private var viewCopy : View? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    if(viewCopy!=null)
        return viewCopy