ViewModel-Übersicht (Ansichten)

Konzepte und Jetpack Compose-Implementierung

Die ViewModel Klasse ist ein State Holder für die Geschäftslogik oder die Bildschirmebene. Sie stellt den Status für die Benutzeroberfläche bereit und kapselt die zugehörige Geschäftslogik. Ihr Hauptvorteil besteht darin, dass sie den Status im Cache speichert und bei Konfigurationsänderungen beibehält. Das bedeutet, dass die Benutzeroberfläche beim Wechsel zwischen Aktivitäten oder nach Konfigurationsänderungen, z. B. beim Drehen des Bildschirms, keine Daten noch einmal abrufen muss.

Vorteile von ViewModels

Die Alternative zu einem ViewModel ist eine einfache Klasse, die die Daten enthält, die auf der Benutzeroberfläche angezeigt werden. Dies kann beim Wechsel zwischen Aktivitäten oder Navigationszielen zu Problemen führen. Dabei werden die Daten zerstört, wenn sie nicht mit dem Mechanismus für den gespeicherten Instanzstatus gespeichert werden. ViewModel bietet eine praktische API für die Datenpersistenz, mit der dieses Problem behoben wird.

Die wichtigsten Vorteile der ViewModel-Klasse sind:

  • Sie ermöglicht es, den UI-Status beizubehalten.
  • Sie bietet Zugriff auf die Geschäftslogik.

Umfang

Wenn Sie ein ViewModel instanziieren, übergeben Sie ihm ein Objekt, das die ViewModelStoreOwner Schnittstelle implementiert. Dabei kann es sich um ein Navigationsziel, einen Navigationsgraphen, eine Aktivität, ein Fragment oder einen anderen Typ handeln, der die Schnittstelle implementiert. Ihr ViewModel ist dann auf den Lifecycle des ViewModelStoreOwner beschränkt. Es bleibt im Arbeitsspeicher, bis der ViewModelStoreOwner endgültig entfernt wird.

Eine Reihe von Klassen sind direkte oder indirekte Unterklassen der Schnittstelle ViewModelStoreOwner. Die direkten Unterklassen sind ComponentActivity, Fragment und NavBackStackEntry. Eine vollständige Liste der indirekten Unterklassen finden Sie in der ViewModelStoreOwner Referenz.

ViewModel implementieren

Im Folgenden finden Sie eine Beispielimplementierung eines ViewModels für einen Bildschirm, auf dem der Nutzer würfeln kann.

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
            )
        );
    }
}

Sie können dann wie folgt auf das ViewModel aus einer Aktivität zugreifen:

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
        });
    }
}