Tạo ViewModel có các phần phụ thuộc Một phần của Android Jetpack.
Làm theo các phương pháp hay nhất về thao tác chèn phần phụ thuộc, ViewModel có thể lấy các phần phụ thuộc làm tham số trong hàm dựng. Đây chủ yếu là các loại từ lớp miền hoặc lớp dữ liệu. Vì khung cung cấp ViewModel, nên bạn cần có một cơ chế đặc biệt để tạo các thực thể của khung đó. Cơ chế đó là giao diện ViewModelProvider.Factory
. Chỉ các cách triển khai giao diện này mới có thể tạo bản sao các ViewModel trong phạm vi phù hợp.
ViewModel với CreationExtras
Nếu một lớp ViewModel
nhận phần phụ thuộc trong hàm khởi tạo của lớp đó, hãy cung cấp một nhà máy triển khai giao diện ViewModelProvider.Factory
.
Ghi đè hàm create(Class<T>, CreationExtras)
để cung cấp bản sao mới của ViewModel.
CreationExtras
cho phép bạn truy cập thông tin liên quan giúp tạo thực thể cho ViewModel. Dưới đây là danh sách các khoá có thể truy cập từ lớp bổ sung:
Khoá | Chức năng |
---|---|
ViewModelProvider.NewInstanceFactory.VIEW_MODEL_KEY |
Cấp quyền truy cập vào khoá tuỳ chỉnh mà bạn đã truyền đến ViewModelProvider.get() . |
ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY |
Cung cấp quyền truy cập vào thực thể của lớp Application . |
SavedStateHandleSupport.DEFAULT_ARGS_KEY |
Cấp quyền truy cập vào Gói đối số mà bạn nên sử dụng để tạo SavedStateHandle . |
SavedStateHandleSupport.SAVED_STATE_REGISTRY_OWNER_KEY |
Cấp quyền truy cập vào SavedStateRegistryOwner đang được dùng để tạo ViewModel . |
SavedStateHandleSupport.VIEW_MODEL_STORE_OWNER_KEY |
Cấp quyền truy cập vào ViewModelStoreOwner đang được dùng để tạo ViewModel . |
Để tạo một phiên bản mới của SavedStateHandle
, hãy sử dụng hàm CreationExtras.createSavedStateHandle()
và truyền hàm đó vào ViewModel.
Sáng tạo bổ sung với APP_KEY
Sau đây là ví dụ về cách cung cấp một thực thể của ViewModel
lấy kho lưu trữ thuộc phạm vi lớp Application
và SavedStateHandle
làm phần phụ thuộc:
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);
}
);
}
Sau đó, bạn có thể sử dụng nhà máy này khi truy xuất một phiên bản của 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)
) {
// ...
}
Ngoài ra, hãy sử dụng DSL nhà máy của ViewModel
để tạo các nhà máy bằng cách sử dụng API Kotlin đúng cách hơn:
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
)
}
}
}
}
Truyền tham số tuỳ chỉnh dưới dạng CreationExtras
Bạn có thể truyền các phần phụ thuộc đến ViewModel
thông qua CreationExtras
bằng cách tạo khoá tuỳ chỉnh.
Điều này có thể hữu ích nếu ViewModel
phụ thuộc vào các đối tượng không thể truy cập thông qua lớp Application
và APPLICATION_KEY
. Ví dụ về điều này là khi ViewModel
được tạo bên trong mô-đun Kotlin Đa nền tảng và do đó không có quyền truy cập vào các phần phụ thuộc Android.
Trong ví dụ này, ViewModel
xác định một khoá tuỳ chỉnh và sử dụng khoá đó trong 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,
)
}
}
}
}
Bạn có thể tạo bản sao ViewModel
bằng CreationExtras.Key
từ một ViewModelStoreOwner
như ComponentActivity
, Fragment
hoặc NavBackStackEntry
hoặc bằng 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,
)
}
Nhà máy (factory) dành cho phiên bản ViewModel trước phiên bản 2.5.0
Nếu đang sử dụng phiên bản ViewModel
cũ hơn phiên bản 2.5.0, bạn cần cung cấp các nhà máy (trạng thái ban đầu) từ một tập hợp con các lớp mở rộng ViewModelProvider.Factory
và triển khai hàm create(Class<T>)
. Tuỳ thuộc vào phần phụ thuộc mà ViewModel
cần, bạn cần mở rộng một lớp khác từ:
AndroidViewModelFactory
nếu cần có lớpApplication
.AbstractSavedStateViewModelFactory
nếu cần truyềnSavedStateHandle
làm phần phụ thuộc.
Nếu không cần Application
hoặc SavedStateHandle
, bạn chỉ cần mở rộng từ ViewModelProvider.Factory
.
Ví dụ sau đây sử dụng một AbstractSavedStateViewModelFactory
cho ViewModel có kho lưu trữ và loại SavedStateHandle
làm phần phụ thuộc:
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);
}
}
Sau đó, bạn có thể sử dụng nhà máy (trạng thái ban đầu) để truy xuất 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
)
)
) {
// ...
}
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Mô-đun trạng thái đã lưu cho ViewModel
- Lưu trạng thái giao diện người dùng
- Tổng quan về LiveData