文档https://developer.android.com/topic/libraries/architecture/viewmodel#sharing描述了如何在不同的片段之间共享相同的ViewModel。
我的单个活动应用中有一些复杂的页面,其中包含容器和标签片段。每个此类页面都有自己的ViewModel,应该与所有包含的片段共享。
这里的关键技巧是使用Activity而不是Fragment来保存我的ViewModel。
问题在于我的“活动”可以有多个具有自己模型的页面,并且始终保持特定页面的视图模型是浪费设备资源。
当用户离开页面时,是否有任何方法可以控制ViewModel的生命周期以销毁它?
我想使用容器片段代替Activity:
model = ViewModelProviders.of(getPageContainerFragment()).get(SharedViewModel.class);
但是发现这个想法不太好,因为所有子片段都应该了解父级,而这可能不是很好。
是否有其他方法可以正确处理这种情况?
答案 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仅在您在这些片段之间浏览时才存在,并在离开它们时被销毁
假设您的应用程序包含这些片段,
并且您希望在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
中找到更多详细信息