Présentation de ViewModel (Vues)

Concepts et implémentation de Jetpack Compose

La classe ViewModel est une logique métier ou un conteneur d'état au niveau de l'écran holder. Elle expose l'état au niveau de l'UI et encapsule la logique métier associée. Son principal avantage est qu'elle assure la mise en cache et la persistance de l'état en cas de modification de la configuration. Cela signifie que votre interface utilisateur n'a pas besoin de récupérer à nouveau les données lorsque vous passez d'une activité à une autre ou suite à une modification de la configuration, par exemple en cas de rotation de l'écran.

Avantages de ViewModel

L'alternative à un ViewModel est une classe simple qui contient les données que vous affichez dans l'interface utilisateur. Cette méthode peut s'avérer problématique lors du passage d'une activité ou d'une destination de navigation à une autre. Elle détruit ces données si vous ne les stockez pas au moyen du mécanisme d'enregistrement de l'état de l'instance. ViewModel fournit une API pratique pour assurer la persistance des données qui résout ce problème.

La classe ViewModel présente principalement deux avantages :

  • Elle vous permet de conserver l'état de l'UI.
  • Elle donne accès à la logique métier.

Champ d'application

Lorsque vous instanciez un ViewModel, vous lui transmettez un objet qui implémente l'interface ViewModelStoreOwner. Il peut s'agir d'une destination ou d'un graphique de navigation, d'une activité, d'un fragment, ou de tout autre type qui implémente l'interface. Votre ViewModel s'applique ensuite au Lifecycle du ViewModelStoreOwner. Il reste en mémoire jusqu'à ce que son ViewModelStoreOwner disparaisse définitivement.

Une plage de classes représente soit des sous-classes directes, soit des sous-classes indirectes de l'interface ViewModelStoreOwner. Les sous-classes directes sont ComponentActivity, Fragment et NavBackStackEntry. Pour obtenir la liste complète des sous-classes indirectes, consultez la ViewModelStoreOwner documentation de référence.

Implémenter un ViewModel

Voici un exemple d'implémentation d'un ViewModel pour un écran permettant à l'utilisateur de lancer des dés.

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

Vous pouvez ensuite accéder au ViewModel à partir d'une activité comme suit :

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