Tổng quan về ViewModel (Khung hiển thị)
Các khái niệm và cách triển khai Jetpack Compose
Lớp ViewModel là một logic kinh doanh hoặc phần tử giữ trạng thái cấp màn hình. Lớp này hiển thị trạng thái cho giao diện người dùng và đóng gói logic kinh doanh liên quan.
Ưu điểm chính của lớp này là khả năng lưu trạng thái vào bộ nhớ đệm và duy trì trạng thái đó khi có các thay đổi về cấu hình. Điều này có nghĩa là giao diện người dùng không phải tìm nạp lại dữ liệu khi di chuyển giữa các hoạt động hoặc áp dụng các thay đổi về cấu hình, chẳng hạn như khi xoay màn hình.
Lợi ích của ViewModel
Lựa chọn thay thế cho ViewModel là một lớp thuần tuý lưu giữ dữ liệu mà bạn hiển thị trong giao diện người dùng. Điều này có thể trở thành vấn đề khi di chuyển giữa các hoạt động hoặc đích đến Điều hướng (Navigation). Thao tác này sẽ huỷ dữ liệu đó nếu bạn không lưu trữ dữ liệu bằng cơ chế trạng thái của thực thể đã lưu. ViewModel cung cấp một API thuận tiện để lưu trữ lâu dài dữ liệu giúp giải quyết vấn đề này.
Về cơ bản, lớp ViewModel mang lại 2 lợi ích chính:
- Lớp này cho phép bạn duy trì trạng thái giao diện người dùng.
- Lớp này cung cấp quyền truy cập vào logic kinh doanh.
Phạm vi
Khi tạo bản sao của ViewModel, bạn sẽ truyền lớp này vào đối tượng sẽ triển khai giao diện ViewModelStoreOwner. Đó có thể là đích đến Điều hướng, biểu đồ Điều hướng, hoạt động, mảnh hoặc bất kỳ loại nào khác triển khai giao diện. Sau đó, ViewModel của bạn được xác định phạm vi là Lifecycle của ViewModelStoreOwner. Lớp này vẫn nằm trong bộ nhớ cho đến khi ViewModelStoreOwner biến mất vĩnh viễn.
Một loạt các lớp có thể là lớp con trực tiếp hoặc gián tiếp của giao diện ViewModelStoreOwner. Các lớp con trực tiếp là ComponentActivity, Fragment và NavBackStackEntry.
Để biết danh sách đầy đủ các lớp con gián tiếp, hãy xem tài liệu tham khảo về ViewModelStoreOwner.
Triển khai một ViewModel
Sau đây là ví dụ về cách triển khai ViewModel cho một màn hình cho phép người dùng đổ xúc xắc.
Kotlin
data class DiceUiState(
val firstDieValue: Int? = null,
val secondDieValue: Int? = null,
val numberOfRolls: Int = 0,
)
class DiceRollViewModel : ViewModel() {
// Expose screen UI state
private val _uiState = MutableStateFlow(DiceUiState())
val uiState: StateFlow<DiceUiState> = _uiState.asStateFlow()
// Handle business logic
fun rollDice() {
_uiState.update { currentState ->
currentState.copy(
firstDieValue = Random.nextInt(from = 1, until = 7),
secondDieValue = Random.nextInt(from = 1, until = 7),
numberOfRolls = currentState.numberOfRolls + 1,
)
}
}
}
Java
public class DiceUiState {
private final Integer firstDieValue;
private final Integer secondDieValue;
private final int numberOfRolls;
// ...
}
public class DiceRollViewModel extends ViewModel {
private final MutableLiveData<DiceUiState> uiState =
new MutableLiveData(new DiceUiState(null, null, 0));
public LiveData<DiceUiState> getUiState() {
return uiState;
}
public void rollDice() {
Random random = new Random();
uiState.setValue(
new DiceUiState(
random.nextInt(7) + 1,
random.nextInt(7) + 1,
uiState.getValue().getNumberOfRolls() + 1
)
);
}
}
Sau đó, bạn có thể truy cập ViewModel trong một hoạt động như sau:
Kotlin
import androidx.activity.viewModels
class DiceRollActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same DiceRollViewModel instance created by the first activity.
// Use the 'by viewModels()' Kotlin property delegate
// from the activity-ktx artifact
val viewModel: DiceRollViewModel by viewModels()
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect {
// Update UI elements
}
}
}
}
}
Java
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same MyViewModel instance created by the first activity.
DiceRollViewModel model = new ViewModelProvider(this).get(DiceRollViewModel.class);
model.getUiState().observe(this, uiState -> {
// update UI
});
}
}
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Sử dụng coroutine của Kotlin với các thành phần nhận biết vòng đời
- Lưu trạng thái giao diện người dùng
- Tải và hiển thị dữ liệu được phân trang