Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ViewModel and process death

Why it is recommend to use the ViewModel architecture component if it does not handle process death?

For example, if I save state with onSaveInstanceState, the state persists both for configuration change and process death while ViewModel only survives configuration change. To survive process death, I need to get the state from the ViewModel and use the same onSaveInstanceState mechanism.

What am I missing?

like image 889
Pavel Poley Avatar asked Sep 07 '26 21:09

Pavel Poley


1 Answers

Why it is recommend to use the ViewModel architecture component if it does not handle process death?

What am I missing?

You were right until January 2020 when, finally, Google released androidx.lifecycle:lifecycle-viewmodel-savedstate and then made the AndroidX Activity, Fragment and Navigation latest library versions provide SavedStateViewModelFactory as the default ViewModelProvider.Factory.

Now you can provide a SavedStateHandle into your ViewModel which can help with persisting/restoring stuff across process death.

class MyViewModel(private val savedStateHandle: SavedStateHandle): ViewModel() {
    val someState: MutableLiveData<String> = savedStateHandle.getLiveData("someState")
}

or

class MyAndroidViewModel(application: Application, private val savedStateHandle: SavedStateHandle): AndroidViewModel(application) {
    val someState: MutableLiveData<String> = savedStateHandle.getLiveData("someState")
}

And these would just work via their default constructors as SavedStateViewModelFactory creates them via reflection.

If you need a SavedStateHandle and also additional parameters, then instead of using a default ViewModelProvider.Factory, you can instead extend from AbstractSavedStateViewModelFactory that will give you a SavedStateHandle that actually works and persists/restores across process death automatically.

val viewModel = ViewModelProvider(this, myAbstractSavedStateViewModelFactoryImpl).get(MyViewModel::class.java)

Or with KTX things

private val viewModel by viewModels { myAbstractSavedStateViewModelFactoryImpl }

You can also scope ViewModels to a Jetpack Navigation's NavGraph, that's a bit trickier but doable:

inline fun <reified T : ViewModel> SavedStateRegistryOwner.createAbstractSavedStateViewModelFactory(
    arguments: Bundle,
    crossinline creator: (SavedStateHandle) -> T
): ViewModelProvider.Factory {
    return object : AbstractSavedStateViewModelFactory(this, arguments) {
        @Suppress("UNCHECKED_CAST")
        override fun <T : ViewModel?> create(
            key: String, modelClass: Class<T>, handle: SavedStateHandle
        ): T = creator(handle) as T
    }
}

inline fun <reified T : ViewModel> Fragment.navGraphSavedStateViewModels(
    @IdRes navGraphId: Int,
    crossinline creator: (SavedStateHandle) -> T
): Lazy<T> {
    // Wrapped in lazy to not search the NavController each time we want the backStackEntry
    val backStackEntry by lazy { findNavController().getBackStackEntry(navGraphId) }

    return createViewModelLazy(T::class, storeProducer = {
        backStackEntry.viewModelStore
    }, factoryProducer = {
        backStackEntry.createAbstractSavedStateViewModelFactory(
            arguments = backStackEntry.arguments ?: Bundle(), creator = creator
        )
    })
}

Then

class MyFragment: Fragment() {
    private val mySharedViewModel by navGraphSavedStateViewModels(R.id.registration_graph) { handle ->
        MySharedViewModel(handle)
    }
}
like image 60
EpicPandaForce Avatar answered Sep 10 '26 12:09

EpicPandaForce



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!