L’architecture MVVM sous Android se traduit par l’utilisation de ViewModel pour gérer l’état de l’UI et faire le liens avec les données.

Les viewModels sont des classes gérées par le système Android, elles sont les particularités suivantes :
viewModelScope)ViewModelProviderPour respecter la logique MVVM vos ViewModel doivent :
viewModels sont faits pour être observés par les composants de l’UI et non liés fortements à eux.viewModels ne doivent pas contenir de références à des vues (TextView, Button, etc.)viewModel, elle doit passer par des fonctions dédiées.💡 Astuce
Ayez la documentation suivante sous les yeux pour vous aider durant vos implémentations : https://developer.android.com/topic/libraries/architecture/viewmodel?hl=fr
Comment lire les données d’un viewModel dans une vue ?

Pour pouvoir pleinement fonctionner, les viewModels se reposent sur le pattern Pub/Sub (Publisher/Subscriber) pour notifier les composants de l’UI des changements d’état. Il existe plusieurs outils pour mettre en place ce pattern sur Android / Kotlin :
Les 3 outils ont leur propre particularités, mais le principe reste le même : un composant s’abonne à un Publisher (le viewModel) pour être notifié des changements d’état.
Comment transmettre les événements utilisateurs à un viewModel ?

La c’est beaucoup plus simple, il suffit de créer des fonctions dans le viewModel qui seront appelées par les composants de l’UI pour modifier l’état.
🚨 Attention
Une règle d’or : Ne jamais modifier l’état d’un viewModel directement depuis un composant de l’UI.
viewModel// ViewModel.kt
class MyViewModel: ViewModel() {
private val _counter = MutableStateFlow(0)
val counter: StateFlow<Int> = _counter
fun incrementCounter() {
_counter.value++
}
}
MyComposable// View.kt
@Composable
fun MyComposable(viewModel: MyViewModel) {
val counter by viewModel.counter.collectAsState() // Transformation d'un événement en état
Button(onClick = { viewModel.incrementCounter() }) {
Text("Click me $counter")
}
}
viewModel ?On ne doit pas instancier directement un viewModel, on doit passer par un ViewModelProvider.
Cela permet au système Android de gérer le cycle de vie du viewModel correctement.
Ainsi un viewModel qui serait déjà instancié ne le serait pas à nouveau, évitant fuite mémoire et erreur d’accès. Un viewModel qui ne serait plus utilisé serait détruit.
🛑 Attention
Si vous tenter de mettre ce code et de lancer l’app, cela ne marchera pas.
Il vous faudra ajouter la dépendance androidx.lifecycle:lifecycle-viewmodel-compose pour que cela fonctionne.
// View.kt
val viewModel = viewModel<MyViewModel>()
Si vous avez besoin de passer des paramètres à votre viewModel, vous pouvez utiliser la syntaxe suivante :
// View.kt
val viewModel = viewModel<MyViewModel>(factory = MyViewModel.provideFactory(param1))
Et la factory, qui par convention est un singleton interne au viewModel :
// ViewModel.kt
class MyViewModel(myParamInViewModel: String) : AndroidViewModel() {
companion object {
fun provideFactory(myParam: String): ViewModelProvider.Factory {
return 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])
return MyViewModel(
myParamInViewModel = myParam,
(application as MyApplication)
) as T
}
}
}
}
private val _counter = MutableStateFlow(0)
val counter: StateFlow<Int> = _counter
fun incrementCounter() {
_counter.value++
}
}