Android JetPack的共享ViewModel生命周期

时间:2018-11-10 06:33:30

标签: android android-fragments android-architecture-components android-jetpack model-view

文档https://developer.android.com/topic/libraries/architecture/viewmodel#sharing描述了如何在不同的片段之间共享相同的ViewModel。

我的单个活动应用中有一些复杂的页面,其中包含容器和标签片段。每个此类页面都有自己的ViewModel,应该与所有包含的片段共享。

这里的关键技巧是使用Activity而不是Fragment来保存我的ViewModel。

问题在于我的“活动”可以有多个具有自己模型的页面,并且始终保持特定页面的视图模型是浪费设备资源。

当用户离开页面时,是否有任何方法可以控制ViewModel的生命周期以销毁它?

我想使用容器片段代替Activity:

model = ViewModelProviders.of(getPageContainerFragment()).get(SharedViewModel.class);

但是发现这个想法不太好,因为所有子片段都应该了解父级,而这可能不是很好。

是否有其他方法可以正确处理这种情况?

2 个答案:

答案 0 :(得分:1)

如果我做对了,您的问题是“如何释放资源”而不是“如何清除视图模型”。
因此,您可以使视图模型尽可能轻,像这样:

abstract class MyViewModel: ViewModel() {
    abstract fun freeResources()
}

当页面更改时,在您的vm.freeResources()OnPageChangeListener或您使用的任何侦听器中调用OnTabSelectedListener
在这种情况下,您应该使用活动范围获取viewModel。

或者,如果您真的希望您的视图模型为onCleared(),然后创建新的视图模型,我建议您使用scoped-vm库。它允许您为由字符串名称标识的范围请求视图模型。

ScopedViewModelProviders
     .forScope(fragment, "scope")
     .of(activity)
     .get(MyViewModel::class.java)

作用域被删除(该视图中的视图模型也将被清除)。因此,请为您的页面使用不同的范围。
但是,在这种情况下,您应该仔细检查片段的生命周期:如果您的PagerAdapter保留了片段以供重复使用,则范围将永远不会被清除,只有手动方法才能为您提供帮助。

答案 1 :(得分:1)

由于您使用的是Android Jetpack,因此我可以假定您也使用了导航组件。

如果希望ViewModel仅在处于某些片段中时保持活动状态,则可以为这些片段创建导航图,以便共享的ViewModel仅在您在这些片段之间浏览时才存在,并在离开它们时被销毁

假设您的应用程序包含这些片段,

  • VehicleFragment:在此片段中,您可以使用制表符(SedanFragment,PickupFragment, OffroadFragment等)
  • UserProfileFragment
  • LoginFragment

并且您希望在Fragment Vehicles及其不同选项卡之间浏览时保持ViewModel处于活动状态。

好吧,像这样为他们创建一个嵌套的导航图。

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_navigation.xml"
    app:startDestination="@id/MainFragment">

    <fragment
        android:id="@+id/MainFragment"
        android:name="com.fortatic.apps.guesstheword.ui.welcome.MainFragment"
        android:label="MainFragment"
        tools:layout="@layout/fragment_main">
        <action
            android:id="@+id/action_mainFragment_to_vehicleGraph"
            app:destination="@id/vehicleGraph" />
    </fragment>

    <navigation
        android:id="@+id/vehicleGraph"
        app:startDestination="@id/vehicleFragment" >
        <fragment
            android:id="@+id/vehicleFragment"
            android:name="com.fortatic.apps.guesstheword.ui.game.VehicleFragment"
            android:label="VehicleFragment"
            tools:layout="@layout/fragment_vehicle">
            <action
                android:id="@+id/action_fragmentVehicle_to_sedanFragment"
                app:destination="@id/sedanFragment"/>
            <action
                android:id="@+id/action_fragmentVehicle_to_pickupsFragment"
                app:destination="@id/pickupsFragment"/>
            <action
                android:id="@+id/action_fragmentVehicle_to_offroadFragment"
                app:destination="@id/offroadFragment"/>        
        </fragment>
        <fragment
            android:id="@+id/sedanFragment"
            android:name="com.fortatic.apps.guesstheword.ui.score.SedanFragment"
            android:label="SedanFragment"
            tools:layout="@layout/fragment_sedan">
            ...
        </fragment>
        <fragment
            android:id="@+id/pickupsFragment"
            android:name="com.fortatic.apps.guesstheword.ui.score.PickupFragment"
            android:label="PickupFragment"
            tools:layout="@layout/fragment_pickups">
            ...
        </fragment>
        <fragment
            android:id="@+id/offroadFragment"
            android:name="com.fortatic.apps.guesstheword.ui.score.OffroadFragment"
            android:label="OffroadFragment"
            tools:layout="@layout/fragment_offroad">
            ...
        </fragment>
    </navigation>
</navigation>

创建嵌套的导航图后,只需使用以下方法请求ViewModel实例:

private val mySharedViewModel: SharedViewModel by navGraphViewModels(R.id.myNestedGraph) {
    //defaultViewModelProviderFactory or the ViewModelProvider.Factory you are using.
}

您可以在此answer

中找到更多详细信息