Sobes.tech
Middle

How to save the state of a ViewModel in Android architecture components?

sobes.tech AI

Answer from AI

The state of ViewModel can be saved in several ways:

  1. Using SavedStateHandle: The preferred method for saving small amounts of data needed to restore state after process destruction. SavedStateHandle provides a map-like interface for saving and retrieving data.

    class MyViewModel(private val state: SavedStateHandle) : ViewModel() {
    
        private val _name = state.getLiveData<String>("name")
        val name: LiveData<String> = _name
    
        fun saveName(newName: String) {
            state.set("name", newName)
        }
    }
    
  2. Saving state in a bundle (Bundle): Used in conjunction with onSaveInstanceState to save data of the Activity or Fragment, not directly of ViewModel. These data can then be used to initialize the ViewModel when it is created.

    // In Activity or Fragment
    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        // Saving data that will later be used to initialize ViewModel
        outState.putString("some_data_for_vm", "important value")
    }
    
    // Using data in ViewModel (via factory)
    class MyViewModelFactory(private val initialData: String) : ViewModelProvider.Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            if (modelClass.isAssignableFrom(MyViewModel::class.java)) {
                @Suppress("UNCHECKED_CAST")
                return MyViewModel(initialData) as T
            }
            throw IllegalArgumentException("Unknown ViewModel class")
        }
    }
    
    class MyViewModel(private val initialData: String) : ViewModel() {
        // Using initialData to restore state
    }
    
  3. Saving data in persistent storage: For saving more complex or larger data volumes, you can use SharedPreferences, databases (e.g., Room), or files. ViewModel can interact with a repository that manages access to these data.

    class MyViewModel(private val userRepository: UserRepository) : ViewModel() {
        fun saveUser(user: User) {
            userRepository.saveUser(user)
        }
    
        fun getUser(id: Long): LiveData<User> {
            return userRepository.getUser(id)
        }
    }
    
    // Example UserRepository
    class UserRepository(private val userDao: UserDao) {
        fun saveUser(user: User) {
            // Logic to save in database
        }
    
        fun getUser(id: Long): LiveData<User> {
            // Logic to retrieve from database
        }
    }
    

The choice of method depends on the type and volume of data being saved, as well as the scenarios for restoring state (e.g., process destruction vs configuration change). SavedStateHandle is the most suitable for saving state that needs to survive process destruction and restore UI.