Tworzenie obiektów ViewModel z zależnościami (widoki), części Androida Jetpack.
Pojęcia i implementacja w Jetpack Compose
Zgodnie ze sprawdzonymi metodami wstrzykiwania zależności obiekty ViewModel mogą przyjmować zależności jako parametry w konstruktorze. Są to głównie typy z warstw domeny lub danych. Ponieważ framework udostępnia obiekty ViewModel, do tworzenia ich instancji jest potrzebny specjalny mechanizm. Tym mechanizmem jest ViewModelProvider.Factory interfejs. Tylko implementacje tego interfejsu mogą tworzyć instancje ViewModel w odpowiednim zakresie.
ViewModel z CreationExtras
Jeśli klasa ViewModel otrzymuje zależności w konstruktorze, podaj fabrykę, która implementuje interfejs ViewModelProvider.Factory.
Zastąp funkcję create(Class<T>, CreationExtras), aby utworzyć nową instancję ViewModel.
CreationExtras z APPLICATION_KEY
Oto przykład sposobu udostępniania instancji ViewModel, która przyjmuje repozytorium w zakresie klasy Application i SavedStateHandle jako zależności:
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);
}
);
}
Następnie możesz użyć tej fabryki podczas pobierania instancji 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
}
Przekazywanie parametrów niestandardowych jako CreationExtras
Zależności możesz przekazywać do ViewModel za pomocą CreationExtras, tworząc klucz niestandardowy.
Może to być przydatne, jeśli ViewModel zależy od obiektów, które nie są dostępne za pomocą klasy Application i APPLICATION_KEY. Przykładem takiej sytuacji jest utworzenie ViewModel w module Kotlin Multiplatform, który nie ma dostępu do zależności Androida.
W tym przykładzie element ViewModel definiuje klucz niestandardowy i używa go w elemencie 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,
)
}
}
}
}
Możesz utworzyć instancję ViewModel z CreationExtras.Key z ViewModelStoreOwner, np. ComponentActivity, Fragment lub 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]
Fabryki dla ViewModel w wersji starszej niż 2.5.0
Jeśli używasz wersji ViewModel starszej niż 2.5.0, musisz podać fabryki z podzbioru klas, które rozszerzają ViewModelProvider.Factory, i zastosować funkcję create(Class<T>). W zależności od tego, jakich zależności potrzebuje ViewModel, należy rozszerzyć inną klasę:
AndroidViewModelFactory, jeśli potrzebne są zajęciaApplication.AbstractSavedStateViewModelFactory, jeśliSavedStateHandlema być przekazywany jako zależność.
Jeśli nie potrzebujesz Application ani SavedStateHandle, po prostu przedłuż od ViewModelProvider.Factory.
W przykładzie poniżej użyto AbstractSavedStateViewModelFactory w przypadku elementu ViewModel, który przyjmuje repozytorium i typ SavedStateHandle jako zależność:
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);
}
}
Następnie możesz użyć fabryki, aby pobrać 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
}
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy język JavaScript jest wyłączony.
- Moduł Saved State dla ViewModel
- Zapisywanie stanów interfejsu
- Omówienie LiveData