【问题标题】:ViewModel scoped to Fragment does not get destroyed when Fragment gets reloaded重新加载 Fragment 时,范围为 Fragment 的 ViewModel 不会被破坏
【发布时间】:2019-11-25 17:12:25
【问题描述】:

我的应用允许用户提交表单(Androidx 片段)来保存数据。表单提交约 30 次后,应用程序内存不足并崩溃。内存转储的比较表明,问题的根源之一是与表单的片段关联的 ViewModel 在提交表单时没有被破坏。

ViewModel 当前使用 Fragment 的 onViewCreated() 方法中的 'this' 关键字限定在 Fragment 的范围内:

    vm = new ViewModelProvider(this).get(AddInventoryVM.class);

当用户提交表单时,会使用 Android Architecture Components 中的 Android Navigation 重新加载该 Fragment,以导航到同一 Fragment。

    navController.navigate(R.id.addInventoryFragment, null);

在此过渡期间,ViewModel 的实例不会被垃圾回收。 onViewCreated() 被调用并创建了一个新的 ViewModel 实例 - 当这种情况多次发生时会导致内存问题。 'onDestroy()' 不会被调用,但onDestroyView() 在转换期间会被调用。

原因可能是 Fragment 实例在转换期间没有被破坏(导致 ViewModel 没有被垃圾收集) - 只有 Fragment 的视图被破坏。但是,如果是这种情况,那么事情就不会加起来 - Android 不会在转换时重用现有的 ViewModel 而不是创建一个新的吗?

尽管存在上述差异,但将 ViewModel 限定为 Fragment 的 ViewLifecycleOwner() 是否是解决问题的好方法?

所以改变这个:

    vm = new ViewModelProvider(this).get(AddInventoryVM.class);

到这里:

    vm = new ViewModelProvider(getViewLifecycleOwner()).get(AddInventoryVM.class);

【问题讨论】:

  • navigate(R.id.addInventoryFragment, null) 只是为您的 Fragment 创建一个新实例(以及新 Fragment 的新 ViewModel)。是什么让您认为这会删除之前的 Fragment?
  • navigate 向前导航,但除非您使用popBackstack,否则您不会在没有“BACK”导航的情况下杀死以前的片段。
  • @ianhanniballake 起初,我的理解是当 Fragment 不再显示时,它会被销毁。这显然是不正确的。我们如何销毁 Fragment 和关联的 ViewModel?

标签: android android-fragments android-lifecycle


【解决方案1】:

根据Navigate to a destination documentation

Android 会维护一个返回堆栈,其中包含您访问过的目的地。当用户打开应用程序时,应用程序的第一个目的地被放置在堆栈中。每次调用 navigate() 方法都会在堆栈顶部放置另一个目标。

因此,当您调用navController.navigate(R.id.addInventoryFragment, null); 时,您将添加库存片段的全新实例添加到后台堆栈,这意味着您的后台堆栈现在有两个副本。如果您再次拨打navigate(),您将获得三份,然后是四份,以此类推。

您可以使用use popUpTo,或者,如果您知道自己总是将片段替换为自身,请使用setLaunchSingleTop(true)

NavOptions options = new NavOptions.Builder()
    .setLaunchSingleTop(true)
    .build();
navController.navigate(R.id.addInventoryFragment, null, options);

(如果您使用<acction> in Navigation XML,您将使用app:launchSingleTop="true" 做同样的事情)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多