Shared ViewModel lifecycle for Android JetPack

后端 未结 2 1184
攒了一身酷
攒了一身酷 2021-02-08 15:53

The documentation https://developer.android.com/topic/libraries/architecture/viewmodel#sharing describes how we can share the same ViewModel across the different Fragments.

相关标签:
2条回答
  • 2021-02-08 16:37

    If I get it right, your question is "how to free up resources" not "how to clear viewmodel".
    So, you can make your viewmodels as light as possible, like this:

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

    and call vm.freeResources() in your OnPageChangeListener or OnTabSelectedListener or whichever listener you use, when page is changed.
    In this case your should obtain viewModel using activity scope.

    Alternatively, if you really want your viewmodel to be onCleared() and then the new one created, I can suggest using scoped-vm library. It allows your to request viewmodels for a scope identified by a string name.

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

    Scope gets cleared (so are viewmodels in it) as soon as last fragment that requested something from that scope gets destroyed. So use different scopes for your pages.
    But, in this case you should double-check the lifecycle of your fragments: if your PagerAdapter holds them for re-use, the scope will never be cleared, and only manual approach will help you.

    0 讨论(0)
  • 2021-02-08 16:44

    Since you are using Android Jetpack, I can assume that you also use Navigation Component.

    If you want a ViewModel to only stay active when you are in certain fragments, you can create a navigation chart for those fragments, so that the shared ViewModel only lives while you are browsing between those fragments and is destroyed when you leave them.

    Imagine that your app has these fragments,

    • VehicleFragment: inside this fragment you have tabs(SedanFragment, PickupFragment, OffroadFragment, etc.)
    • UserProfileFragment
    • LoginFragment
    • etc.

    And you want to keep a ViewModel alive while you are browsing between Fragment Vehicles and its different tabs.

    Well, create a nested navigation chart for them like this.

    <?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>
    

    Once you have created the nested navigation graph, simply request an instance of ViewModel using:

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

    You can find more details in this answer

    0 讨论(0)
提交回复
热议问题