Tworzenie widoków modelu z zależностями Element Android Jetpack.
Zgodnie ze sprawdzonymi metodami dotyczącymi wstrzykiwania zależności konstruktor ViewModel może przyjmować zależności jako parametry. Są to głównie typy z warstwy domeny lub danych. Framework udostępnia modele ViewModel, więc do tworzenia ich instancji potrzebny jest specjalny mechanizm. Ten mechanizm to interfejs ViewModelProvider.Factory
. Tylko implementacje tego interfejsu mogą tworzyć instancje ViewModels we właściwym zakresie.
Wyświetl modele z dodatkami do tworzenia
Jeśli klasa ViewModel
otrzymuje zależności w swoim konstruktorze, podaj fabrykę, która implementuje interfejs ViewModelProvider.Factory
.
Zastąp funkcję create(Class<T>, CreationExtras)
, aby udostępnić nową instancję ViewModel.
CreationExtras
umożliwia dostęp do odpowiednich informacji, które pomagają utworzyć instancję ViewModel. Oto lista kluczy, do których można uzyskać dostęp z poziomu dodatkowych opcji:
Klucz | Funkcjonalność |
---|---|
ViewModelProvider.NewInstanceFactory.VIEW_MODEL_KEY |
Zapewnia dostęp do klucza niestandardowego przekazanego do ViewModelProvider.get() . |
ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY |
Zapewnia dostęp do instancji klasy Application . |
SavedStateHandleSupport.DEFAULT_ARGS_KEY |
Zapewnia dostęp do zbioru argumentów, których należy użyć do stworzenia SavedStateHandle . |
SavedStateHandleSupport.SAVED_STATE_REGISTRY_OWNER_KEY |
Zapewnia dostęp do SavedStateRegistryOwner , który jest używany do tworzenia ViewModel . |
SavedStateHandleSupport.VIEW_MODEL_STORE_OWNER_KEY |
Zapewnia dostęp do ViewModelStoreOwner , który jest używany do tworzenia ViewModel . |
Aby utworzyć nową instancję SavedStateHandle
, użyj funkcji CreationExtras.createSavedStateHandle()
i przekaż ją do ViewModel.
Dodatki z APPLICATION_KEY
Oto przykład sposobu udostępniania instancji ViewModel
, która przyjmuje repozytorium ograniczone do klasy Application
i SavedStateHandle
jako zależności:
Kotlin
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.CreationExtras
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 = object : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
modelClass: Class<T>,
extras: CreationExtras
): T {
// Get the Application object from extras
val application = checkNotNull(extras[APPLICATION_KEY])
// Create a SavedStateHandle for this ViewModel from extras
val savedStateHandle = extras.createSavedStateHandle()
return MyViewModel(
(application as MyApplication).myRepository,
savedStateHandle
) as T
}
}
}
}
Java
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 wystąpienia 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
}
Jetpack Compose
import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
modifier: Modifier = Modifier,
viewModel: MyViewModel = viewModel(factory = MyViewModel.Factory)
) {
// ...
}
Możesz też użyć DSL fabryki ViewModel
, aby tworzyć fabryki za pomocą bardziej idiomatycznego interfejsu Kotlin:
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
)
}
}
}
}
Przekazywanie parametrów niestandardowych jako dodatkowych informacji o tworzeniu
Zależności można przekazywać do ViewModel
za pomocą CreationExtras
, tworząc klucz niestandardowy.
Może to być przydatne, gdy ViewModel
zależy od obiektów, które są niedostępne za pomocą klasy Application
i APPLICATION_KEY
. Przykładem takiej sytuacji jest sytuacja, gdy ViewModel
jest tworzony w ramach modułu Kotlin Multiplatform i nie ma dostępu do zależności Androida.
W tym przykładzie element ViewModel
definiuje klucz niestandardowy i używa go w elementzie 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,
)
}
}
}
}
Obiekt ViewModel
możesz utworzyć za pomocą obiektu CreationExtras.Key
z ViewModelStoreOwner
, takiego jak ComponentActivity
, Fragment
lub NavBackStackEntry
, albo za pomocą Jetpack Compose.
Kotlin
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]
Jetpack Compose
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,
)
}
Fabryki dla wersji ViewModel 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ą zakres ViewModelProvider.Factory
, i zaimplementować funkcję create(Class<T>)
. W zależności od tego, jakich zależności potrzebuje ViewModel
, należy rozszerzyć inną klasę:
AndroidViewModelFactory
, jeśli potrzebna jest klasaApplication
.AbstractSavedStateViewModelFactory
, jeśliSavedStateHandle
trzeba przekazać jako zależność.
Jeśli nie potrzebujesz wersji Application
ani SavedStateHandle
, po prostu przedłuż wersję ViewModelProvider.Factory
.
W tym przykładzie użyto typu AbstractSavedStateViewModelFactory
dla widoku modelu, 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
}
Jetpack Compose
import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
modifier: Modifier = Modifier,
viewModel: MyViewModel = viewModel(
factory = MyViewModel.provideFactory(
(LocalContext.current.applicationContext as MyApplication).myRepository,
owner = LocalSavedStateRegistryOwner.current
)
)
) {
// ...
}
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy obsługa JavaScript jest wyłączona
- Moduł zapisanego stanu dla ViewModel
- Zapisywanie stanów interfejsu
- Omówienie LiveData