Tạo ViewModel 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 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()
.createSavedStateHandle()) và truyền hàm đó vào ViewModel.
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
)
}
}
}
}
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 trước 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ộngViewModelProvider.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