Cómo crear ViewModels con dependencias   Parte de Android Jetpack.

Según las prácticas recomendadas para insertar dependencias, los ViewModels pueden tomar dependencias como parámetros en su constructor. En su mayoría, son de los tipos de capas de dominio o datos. Debido a que el framework proporciona los ViewModels, se requiere un mecanismo especial para crear instancias de ellos. Ese mecanismo es la interfaz ViewModelProvider.Factory. Solo las implementaciones de esta interfaz pueden crear instancias de ViewModels en el alcance correcto.

ViewModels con CreationExtras

Si una clase ViewModel recibe dependencias en su constructor, proporciona una fábrica que implemente la interfaz ViewModelProvider.Factory. Anula la función create(Class<T>, CreationExtras) para proporcionar una instancia nueva del ViewModel.

CreationExtras te permite acceder a información relevante que te ayuda a crear una instancia de ViewModel. Esta es una lista de claves a las que se puede acceder desde los extras:

Clave Funcionalidad
ViewModelProvider.NewInstanceFactory.VIEW_MODEL_KEY Proporciona acceso a la clave personalizada que pasaste a ViewModelProvider.get().
ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY Proporciona acceso a la instancia de la clase Application.
SavedStateHandleSupport.DEFAULT_ARGS_KEY Proporciona acceso al paquete de argumentos que debes usar para construir un SavedStateHandle.
SavedStateHandleSupport.SAVED_STATE_REGISTRY_OWNER_KEY Proporciona acceso al SavedStateRegistryOwner que se usa para construir el ViewModel.
SavedStateHandleSupport.VIEW_MODEL_STORE_OWNER_KEY Proporciona acceso al ViewModelStoreOwner que se usa para construir el ViewModel.

Para crear una instancia nueva de SavedStateHandle, usa la función CreationExtras.createSavedStateHandle() y pásala al ViewModel.

CreationExtras con APPLICATION_KEY

A continuación, se muestra un ejemplo de cómo proporcionar una instancia de un ViewModel que toma un repositorio definido para la clase Application y SavedStateHandle como dependencias:

    import androidx.lifecycle.SavedStateHandle
    import androidx.lifecycle.ViewModel
    import androidx.lifecycle.ViewModelProvider
    import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
    import androidx.lifecycle.createSavedStateHandle
    import androidx.lifecycle.viewmodel.initializer
    import androidx.lifecycle.viewmodel.viewModelFactory

    class MyViewModel(
        private val myRepository: MyRepository,
        private val savedStateHandle: SavedStateHandle
    ) : ViewModel() {

        // ViewModel logic
        // ...

        // Define ViewModel factory in a companion object
        companion object {

            val Factory: ViewModelProvider.Factory = viewModelFactory {
                initializer {
                    val savedStateHandle = createSavedStateHandle()
                    val myRepository = (this[APPLICATION_KEY] as MyApplication).myRepository
                    MyViewModel(
                        myRepository = myRepository,
                        savedStateHandle = savedStateHandle
                    )
                }
            }
        }
    }

Luego, puedes usar esta fábrica cuando recuperas una instancia del ViewModel:

import androidx.lifecycle.viewmodel.compose.viewModel

@Composable
fun MyScreen(
    modifier: Modifier = Modifier,
    viewModel: MyViewModel = viewModel(factory = MyViewModel.Factory)
) {
    // ...
}

Cómo pasar parámetros personalizados como CreationExtras

Puedes pasar dependencias a tu ViewModel a través de CreationExtras creando una clave personalizada. Esto puede ser útil si tu ViewModel depende de objetos a los que no se puede acceder a través de la clase Application y APPLICATION_KEY. Un ejemplo de esto es cuando tu ViewModel se crea dentro de un módulo de Kotlin Multiplatform y, por lo tanto, no tiene acceso a las dependencias de Android.

En este ejemplo, ViewModel define una clave personalizada y la usa en ViewModelProvider.Factory.

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory

class MyViewModel(
    private val myRepository: MyRepository,
) : ViewModel() {
    // ViewModel logic

    // Define ViewModel factory in a companion object
    companion object {

        // Define a custom key using the factory function
        val MY_REPOSITORY_KEY = CreationExtras.Key<MyRepository>()

        val Factory: ViewModelProvider.Factory = viewModelFactory {
            initializer {
                // Get the dependency in your factory
                val myRepository = this[MY_REPOSITORY_KEY] as MyRepository
                MyViewModel(
                    myRepository = myRepository,
                )
            }
        }
    }
}

Puedes crear una instancia de un ViewModel con un CreationExtras.Key directamente en tus elementos componibles.

import androidx.lifecycle.viewmodel.MutableCreationExtras
import androidx.lifecycle.viewmodel.compose.viewModel
// ...
@Composable
fun MyApp(myRepository: MyRepository) {
    val extras = MutableCreationExtras().apply {
        set(MyViewModel.MY_REPOSITORY_KEY, myRepository)
    }
    val viewModel: MyViewModel = viewModel(
        factory = MyViewModel.Factory,
        extras = extras,
    )
}

Recursos adicionales

Para obtener más información sobre los ViewModels y las dependencias, consulta los siguientes recursos adicionales:

Documentación

Mira contenido