Cómo crear ViewModels con dependencias (Views) Parte de Android Jetpack.
Conceptos y Jetpack Compose implementation
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 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 static androidx.lifecycle.SavedStateHandleSupport.createSavedStateHandle;
import static androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY;
import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.viewmodel.ViewModelInitializer;
public class MyViewModel extends ViewModel {
public MyViewModel(
MyRepository myRepository,
SavedStateHandle savedStateHandle
) { /* Init ViewModel here */ }
static final ViewModelInitializer<MyViewModel> initializer = new ViewModelInitializer<>(
MyViewModel.class,
creationExtras -> {
MyApplication app = (MyApplication) creationExtras.get(APPLICATION_KEY);
assert app != null;
SavedStateHandle savedStateHandle = createSavedStateHandle(creationExtras);
return new MyViewModel(app.getMyRepository(), savedStateHandle);
}
);
}
Luego, puedes usar esta fábrica cuando recuperas una instancia del ViewModel:
Kotlin
import androidx.activity.viewModels
class MyActivity : AppCompatActivity() {
private val viewModel: MyViewModel by viewModels { MyViewModel.Factory }
// Rest of Activity code
}
Java
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
public class MyActivity extends AppCompatActivity {
MyViewModel myViewModel = new ViewModelProvider(
this,
ViewModelProvider.Factory.from(MyViewModel.initializer)
).get(MyViewModel.class);
// Rest of Activity code
}
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, el ViewModel define una clave personalizada y la usa en el
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 for your dependency
val MY_REPOSITORY_KEY = object : 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 una CreationExtras.Key de un
ViewModelStoreOwner como
ComponentActivity, Fragment o NavBackStackEntry.
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.MutableCreationExtras
// ...
// Use from ComponentActivity, Fragment, NavBackStackEntry,
// or another ViewModelStoreOwner.
val viewModelStoreOwner: ViewModelStoreOwner = this
val myViewModel: MyViewModel = ViewModelProvider.create(
viewModelStoreOwner,
factory = MyViewModel.Factory,
extras = MutableCreationExtras().apply {
set(MyViewModel.MY_REPOSITORY_KEY, myRepository)
},
)[MyViewModel::class]
Fábricas para una versión de ViewModel anterior a la 2.5.0
Si usas una versión de ViewModel anterior a la 2.5.0, debes proporcionar
fábricas de un subconjunto de clases que extiendan ViewModelProvider.Factory
e implementar la función create(Class<T>). Según las dependencias que necesite ViewModel, se debe extender una clase diferente:
AndroidViewModelFactorydesde si se necesita la claseApplication.AbstractSavedStateViewModelFactorydesde si se debe pasarSavedStateHandlecomo dependencia.
Si Application o SavedStateHandle no son necesarios, solo debes extenderlos desde ViewModelProvider.Factory.
En el siguiente ejemplo, se usa un AbstractSavedStateViewModelFactory para un ViewModel que toma un repositorio y un tipo SavedStateHandle como dependencia:
Kotlin
class MyViewModel(
private val myRepository: MyRepository,
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
// ViewModel logic ...
// Define ViewModel factory in a companion object
companion object {
fun provideFactory(
myRepository: MyRepository,
owner: SavedStateRegistryOwner,
defaultArgs: Bundle? = null,
): AbstractSavedStateViewModelFactory =
object : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
): T {
return MyViewModel(myRepository, handle) as T
}
}
}
}
Java
import androidx.annotation.NonNull;
import androidx.lifecycle.AbstractSavedStateViewModelFactory;
import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.ViewModel;
public class MyViewModel extends ViewModel {
public MyViewModel(
MyRepository myRepository,
SavedStateHandle savedStateHandle
) { /* Init ViewModel here */ }
}
public class MyViewModelFactory extends AbstractSavedStateViewModelFactory {
private final MyRepository myRepository;
public MyViewModelFactory(
MyRepository myRepository
) {
this.myRepository = myRepository;
}
@SuppressWarnings("unchecked")
@NonNull
@Override
protected <T extends ViewModel> T create(
@NonNull String key, @NonNull Class<T> modelClass, @NonNull SavedStateHandle handle
) {
return (T) new MyViewModel(myRepository, handle);
}
}
Luego, puedes usar la fábrica para recuperar tu ViewModel:
Kotlin
import androidx.activity.viewModels
class MyActivity : AppCompatActivity() {
private val viewModel: MyViewModel by viewModels {
MyViewModel.provideFactory((application as MyApplication).myRepository, this)
}
// Rest of Activity code
}
Java
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
public class MyActivity extends AppCompatActivity {
MyViewModel myViewModel = new ViewModelProvider(
this,
ViewModelProvider.Factory.from(MyViewModel.initializer)
).get(MyViewModel.class);
// Rest of Activity code
}
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Módulo de estado guardado para ViewModel
- Cómo guardar estados de la IU
- Descripción general de LiveData