Informacje o ViewModel (Views)
Koncepcje i implementacja w Jetpack Compose
Klasa ViewModel to zmienna stanu na poziomie logiki biznesowej lub ekranu. Udostępnia ona stan interfejsowi i hermetyzuje powiązaną logikę biznesową.
Jej główną zaletą jest to, że buforuje stan i zachowuje go podczas zmian konfiguracji. Oznacza to, że interfejs nie musi ponownie pobierać danych podczas przechodzenia między aktywnościami ani po zmianach konfiguracji, np. po obróceniu ekranu.
Korzyści ViewModel
Alternatywą dla ViewModel jest zwykła klasa, która zawiera dane wyświetlane w interfejsie. Może to stanowić problem podczas przechodzenia między aktywnościami lub miejscami docelowymi nawigacji. Jeśli nie zapiszesz danych za pomocą mechanizmu zapisanego stanu instancji, zostaną one zniszczone. ViewModel udostępnia wygodny interfejs API do utrwalania danych, który rozwiązuje ten problem.
Główne korzyści klasy ViewModel są zasadniczo 2:
- Umożliwia utrwalanie stanu interfejsu.
- Zapewnia dostęp do logiki biznesowej.
Zakres
Podczas tworzenia instancji ViewModel przekazujesz jej obiekt, który implementuje interfejs
ViewModelStoreOwner. Może to być miejsce docelowe nawigacji, wykres nawigacji, aktywność, fragment lub dowolny inny typ, który implementuje ten interfejs. ViewModel jest wtedy ograniczony do Lifecycle elementu
ViewModelStoreOwner. Pozostaje w pamięci, dopóki jego ViewModelStoreOwner nie zostanie trwale usunięty.
Szereg klas jest bezpośrednimi lub pośrednimi podklasami interfejsu ViewModelStoreOwner. Bezpośrednie podklasy to
ComponentActivity, Fragment i NavBackStackEntry.
Pełną listę pośrednich podklas znajdziesz w dokumentacji
ViewModelStoreOwner reference.
Implementowanie ViewModel
Poniżej znajdziesz przykładową implementację ViewModel dla ekranu, który umożliwia użytkownikowi rzucanie kostką.
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
)
);
}
}
Następnie możesz uzyskać dostęp do ViewModel z aktywności w ten sposób:
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
});
}
}
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy język JavaScript jest wyłączony.
- Używanie współprogramów Kotlin z komponentami uwzględniającymi cykl życia
- Zapisywanie stanów interfejsu
- Wczytywanie i wyświetlanie danych podzielonych na strony