API di definizione dell'ambito di ViewModel Parte di Android Jetpack.
L'ambito è fondamentale per utilizzare i ViewModel in modo efficace. Ogni ViewModel è associato a un oggetto che implementa l'interfaccia ViewModelStoreOwner. Esistono
diverse API che ti consentono di gestire più facilmente l'ambito dei tuoi ViewModel.
Questo documento descrive alcune delle tecniche chiave che devi conoscere.
Il metodo ViewModelProvider.get() consente di ottenere un'istanza di un ViewModel
con ambito qualsiasi ViewModelStoreOwner. Per gli utenti Kotlin, sono disponibili diverse
funzioni di estensione per i casi d'uso più comuni. Tutte le implementazioni delle funzioni di estensione Kotlin utilizzano l'API ViewModelProvider.
ViewModel con ambito definito sul ViewModelStoreOwner più vicino
Puoi definire l'ambito di un ViewModel in base a un composable, un'attività o
una destinazione di un grafico di navigazione. La funzione
viewModel() in Compose ti consente di ottenere un'istanza di ViewModel
con ambito ViewModelStoreOwner più vicino.
import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( modifier: Modifier = Modifier, // ViewModel API available in lifecycle.lifecycle-viewmodel-compose // The ViewModel is scoped to the closest ViewModelStoreOwner provided // via the LocalViewModelStoreOwner CompositionLocal. In order of proximity, // this could be the destination of a Navigation graph // or the host Activity. viewModel: MyViewModel = viewModel() ) { /* ... */ }
ViewModel con ambito qualsiasi ViewModelStoreOwner
La funzione viewModel() accetta un parametro viewModelStoreOwner facoltativo che puoi utilizzare per specificare a quale ViewModelStoreOwner è associata l'istanza di ViewModel.
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.ViewModelStoreOwner @Composable fun MyScreen( // A custom owner passed in, such as a parent NavBackStackEntry customOwner: ViewModelStoreOwner, // The ViewModel is now scoped to the provided customOwner viewModel: MyViewModel = viewModel(viewModelStoreOwner = customOwner) ) { /* ... */ }
ViewModel con ambito definito per un composable
Puoi utilizzare rememberViewModelStoreOwner() per definire l'ambito di un ViewModel direttamente
nel sito di chiamata di un composable. Ciò è particolarmente utile per i componenti UI che
vengono aggiunti o rimossi dinamicamente dalla schermata in base allo stato, ad esempio gli
elementi di una pagina o di un elenco a caricamento lento. Quando il composable che possiede
ViewModelStoreOwner esce dalla composizione, ViewModelStore
associato viene cancellato e il ViewModel viene eliminato.
Utilizza rememberViewModelStoreOwner() per creare uno store consapevole del ciclo di vita che
sopravvive alle modifiche alla configurazione.
@Composable
fun RememberViewModelStoreOwnerSample() {
// Create a ViewModelStoreOwner scoped to this specific call site.
// When this composable leaves the composition,
// the associated ViewModelStore will be cleared.
val scopedOwner = rememberViewModelStoreOwner()
CompositionLocalProvider(LocalViewModelStoreOwner provides scopedOwner) {
// This ViewModel is scoped to `scopedOwner`.
// It will survive configuration changes but will be cleared when
// the composable is removed from the UI tree.
val viewModel = viewModel { TestViewModel("scoped_data") }
// Use the ViewModel
}
}
Per implementazioni più complesse, come HorizontalPager o casi che richiedono più ambiti indipendenti, utilizza rememberViewModelStoreProvider().
In questo modo puoi generare istanze ViewModelStoreOwner distinte per chiavi diverse (come gli indici di pagina). In questo modo, ogni pagina mantiene il proprio stato ViewModel indipendente.
@Composable
fun RememberViewModelStoreProviderSample() {
val storeProvider = rememberViewModelStoreProvider()
val pages = listOf("Page 1", "Page 2", "Page 3")
HorizontalPager(pageCount = pages.size) { page ->
// Create a ViewModelStoreOwner for the specific page using the provider.
val pageOwner = rememberViewModelStoreOwner(provider = storeProvider, key = page)
CompositionLocalProvider(LocalViewModelStoreOwner provides pageOwner) {
val pageViewModel = viewModel { TestViewModel(pages[page]) }
// Use pageViewModel
}
}
}
ViewModel con ambito nel grafico di navigazione
I grafici di navigazione sono anche proprietari dell'archivio ViewModel. Se utilizzi
Navigation Compose, puoi ottenere un'istanza di un
ViewModel con ambito in un grafico di navigazione con la funzione
getBackStackEntry().
viewModel() recupera l'istanza dal ViewModelStoreOwner più vicino
fornito da LocalViewModelStoreOwner CompositionLocal. In una tipica
applicazione Compose che utilizza Jetpack Navigation, questo proprietario è l'attuale
voce dello stack di navigazione. Ciò significa che il ViewModel rimane in memoria finché
la destinazione è presente nel back stack.
import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyAppNavHost() { // ... composable("myScreen") { backStackEntry -> // Retrieve the NavBackStackEntry of "parentNavigationRoute" val parentEntry = remember(backStackEntry) { navController.getBackStackEntry("parentNavigationRoute") } // Get the ViewModel scoped to the `parentNavigationRoute` Nav graph val parentViewModel: SharedViewModel = viewModel(parentEntry) // ... } }
Se utilizzi Hilt oltre a Jetpack Navigation, puoi utilizzare l'API
hiltNavGraphViewModels(graphId)
come segue.
import androidx.hilt.navigation.compose.hiltViewModel @Composable fun MyAppNavHost() { // ... composable("myScreen") { backStackEntry -> val parentEntry = remember(backStackEntry) { navController.getBackStackEntry("parentNavigationRoute") } // ViewModel API available in hilt.hilt-navigation-compose // The ViewModel is scoped to the `parentNavigationRoute` Navigation graph // and is provided using the Hilt-generated ViewModel factory val parentViewModel: SharedViewModel = hiltViewModel(parentEntry) // ... } }
Risorse aggiuntive
Per scoprire di più su ViewModel e ambito, consulta le seguenti risorse aggiuntive: