导航体系结构组件-OnBackPressed()-Android

时间:2020-08-10 13:02:42

标签: android kotlin android-jetpack navigation-architecture

我在使用Android导航体系结构的过程中不断进步。

当我在最后一个屏幕上按键或在屏幕上放置一个按钮并将按钮功能设置为

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

并单击,我返回上一个片段,但是上一个片段中的onCreateView()方法被再次调用。我期望它保持其正常状态。

我在哪里做错了?

3 个答案:

答案 0 :(得分:2)

您没有做错任何事情,对于片段来说,这种行为是正常的。导航到另一个片段时,片段管理器仅保存事务,而不保存当前片段的状态。

要保存片段的实例状态,您可以覆盖onSaveInstanceState()函数并将数据放入状态包中。 要获取已保存的数据,可以覆盖onActivityCreated()并检查数据是否包含在savedInstanceState捆绑包中。

您可以在此处查看片段生命周期:

enter image description here

答案 1 :(得分:2)

我将分为两部分-

解决方案:

每次返回上一个片段时都不要使视图膨胀。将View保存到局部变量中,并仅对其进行一次充气。由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,起始目的地是“首页片段”。

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

HomeFragment:onAttach:

HomeFragment:onCreate:

HomeFragment:onCreateView:

HomeFragment:onViewCreated:

HomeFragment:onActivityCreated:

HomeFragment:onStart:

HomeFragment:onResume:

关于导航:主页片段--->仪表板片段

DashboardFragment:onAttach:

DashboardFragment:onCreate:

DashboardFragment:onCreateView:

DashboardFragment:onViewCreated:

DashboardFragment:onActivityCreated:

DashboardFragment:onStart:

DashboardFragment:onResume:

HomeFragment:onPause:

HomeFragment:onStop:

HomeFragment:onDestroyView:

关于导航:仪表板片段--->主页片段

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的旧实例。

我仍然认为这种处理方式不是最佳做法,但是直到Google提出类似onFragemntRestore()之类的方式。

另一方面,假设片段每次被删除或替换时都将重新创建,并且您应该使用onSaveInstanceState()在此处恢复状态。

使用ViewModel可以节省保存片段状态并恢复它们的麻烦。 要实际更新视图,必须先使用ViewModel并观察更改以更改视图。

enter image description here 简而言之,如果您有something负责为您的视图提供数据,无论您身在何处,如果您返回原位置而没有任何更改,则something会提供有关您的情况的信息早点看。 somethingViewModel

在同一主题上还有许多其他值得阅读的内容,例如thisthisthis

快乐编码!

答案 2 :(得分: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,将当前状态作为包传递,并在Android系统以包为参数调用onCreateView时重用它。

2-使用包含视图状态信息的ViewModel,该状态信息与Fragment,其View或其父Activity绑定在一起,并随之被破坏。

3-保留片段中onCreateView返回的View对象的副本,并在再次调用onCreateView时将其重用(如果不为null的话)(请谨慎使用,因为某些视图可能会出现重绘的麻烦,例如OSM MapView) :

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