Puoi utilizzare le tue librerie preferite in Compose. Questa sezione descrive come incorporare alcune delle librerie più utili.
Attività
Per utilizzare Compose in un'attività, devi utilizzare
ComponentActivity
,
una sottoclasse di Activity
che fornisce LifecycleOwner
e
componenti appropriati a Compose. Fornisce inoltre API aggiuntive che separano il codice
dai metodi di override nella classe Activity.
Activity Compose
espone queste API ai composable in modo che non sia più necessario eseguire l'override dei metodi al di fuori dei
composable o recuperare un'istanza Activity
esplicita.
Inoltre, queste API garantiscono che vengano inizializzate una sola volta, sopravvivano
alla ricomposizione e vengano pulite correttamente se il componibile viene rimosso dalla
composizione.
Risultato attività
L'API
rememberLauncherForActivityResult()
ti consente di
ottenere un risultato da un'attività
nel tuo componente componibile:
@Composable fun GetContentExample() { var imageUri by remember { mutableStateOf<Uri?>(null) } val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? -> imageUri = uri } Column { Button(onClick = { launcher.launch("image/*") }) { Text(text = "Load Image") } Image( painter = rememberAsyncImagePainter(imageUri), contentDescription = "My Image" ) } }
Questo esempio mostra un semplice contratto
GetContent()
. Se tocchi il pulsante, la richiesta viene avviata. La lambda finale per
rememberLauncherForActivityResult()
viene richiamata quando l'utente seleziona un'immagine e torna all'attività di avvio.
In questo modo viene caricata l'immagine selezionata utilizzando la funzione rememberImagePainter()
di Coil.
Qualsiasi sottoclasse di
ActivityResultContract
può essere utilizzata come primo argomento di
rememberLauncherForActivityResult()
.
Ciò significa che puoi utilizzare questa tecnica per richiedere contenuti dal framework
e in altri pattern comuni. Puoi anche creare i tuoi
contratti personalizzati e utilizzarli con
questa tecnica.
Richiesta delle autorizzazioni di runtime
La stessa API Activity Result e
rememberLauncherForActivityResult()
spiegata sopra può essere utilizzata per
richiedere le autorizzazioni di runtime
utilizzando il contratto
RequestPermission
per una singola autorizzazione o il contratto
RequestMultiplePermissions
per più autorizzazioni.
La libreria Accompanist Permissions può essere utilizzata anche come livello sopra queste API per mappare lo stato attuale concesso per le autorizzazioni nello stato che la tua UI Compose può utilizzare.
Gestione del pulsante Indietro del sistema
Per fornire una navigazione indietro personalizzata
e ignorare il comportamento predefinito del pulsante Indietro del sistema dall'interno del tuo
componente componibile, quest'ultimo può utilizzare un
BackHandler
per intercettare l'evento:
var backHandlingEnabled by remember { mutableStateOf(true) } BackHandler(backHandlingEnabled) { // Handle back press }
Il primo argomento controlla se
BackHandler
è attualmente abilitato. Puoi utilizzare questo argomento per disattivare temporaneamente il gestore
in base allo stato del componente. La lambda finale verrà richiamata se l'utente attiva un evento di sistema Indietro e BackHandler
è attualmente abilitato.
ViewModel
Se utilizzi la libreria Architecture Components
ViewModel, puoi accedere a un
ViewModel
da qualsiasi composable chiamando la
funzione
viewModel()
. Aggiungi la seguente dipendenza al tuo file Gradle:
Groovy
dependencies { implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5' }
Kotlin
dependencies { implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5") }
Puoi quindi utilizzare la funzione viewModel()
nel tuo codice.
class MyViewModel : ViewModel() { /*...*/ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { // use viewModel here }
viewModel()
restituisce un ViewModel
esistente o ne crea uno nuovo. Per impostazione predefinita,
il ViewModel
restituito è limitato all'attività, al fragment o
alla destinazione di navigazione inclusi e viene conservato finché l'ambito è attivo.
Ad esempio, se il composable viene utilizzato in un'attività, viewModel()
restituisce la
stessa istanza finché l'attività non è terminata o il processo non viene interrotto.
class MyViewModel : ViewModel() { /*...*/ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( // Returns the same instance as long as the activity is alive, // just as if you grabbed the instance from an Activity or Fragment viewModel: MyViewModel = viewModel() ) { /* ... */ } @Composable fun MyScreen2( viewModel: MyViewModel = viewModel() // Same instance as in MyScreen ) { /* ... */ }
Linee guida per l'utilizzo
In genere, accedi alle istanze di ViewModel
nei composable a livello di schermata, ovvero vicino a un composable radice chiamato da un'attività, un fragment o una destinazione di un grafico di navigazione. Questo perché ViewModel
s
sono, per impostazione predefinita, limitati a questi oggetti a livello di schermo. Scopri di più sul
ciclo di vita e sull'ambito
dell'ViewModel
qui.
Cerca di evitare di passare istanze di ViewModel
ad altri componenti componibili, in quanto ciò può rendere più difficile il test di questi componenti e può interrompere le anteprime. Passa invece solo i dati
e le funzioni di cui hanno bisogno come parametri.
Puoi utilizzare le istanze ViewModel
per gestire lo stato dei composable a livello di schermata secondaria, ma tieni presente il ciclo di vita e l'ambito di ViewModel
. Se il
componente componibile è autonomo, ti consigliamo di utilizzare Hilt per
inserire ViewModel
ed evitare di dover passare le dipendenze dai componenti componibili
principali.
Se ViewModel
ha dipendenze, viewModel()
accetta un ViewModelProvider.Factory
facoltativo
come parametro.
Per saperne di più su ViewModel
in Compose e su come vengono utilizzate le istanze
con la libreria Navigation Compose o con attività e frammenti,
consulta la documentazione sull'interoperabilità.
Stream di dati
Compose include estensioni per le soluzioni basate su stream più popolari di Android. Ciascuna di queste estensioni viene fornita da un artefatto diverso:
LiveData.observeAsState()
incluso nell'artefattoandroidx.compose.runtime:runtime-livedata:$composeVersion
.Flow.collectAsState()
non richiede dipendenze aggiuntive.Observable.subscribeAsState()
incluso nell'artefattoandroidx.compose.runtime:runtime-rxjava2:$composeVersion
oandroidx.compose.runtime:runtime-rxjava3:$composeVersion
.
Questi artefatti vengono registrati come ascoltatori e rappresentano i valori come
State
. Ogni volta che viene emesso un nuovo valore, Compose ricompone le parti della UI in cui viene utilizzato state.value
. Ad esempio, in questo codice, ShowData
viene ricomposto ogni volta che exampleLiveData
emette un nuovo valore.
// import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { val dataExample = viewModel.exampleLiveData.observeAsState() // Because the state is read here, // MyScreen recomposes whenever dataExample changes. dataExample.value?.let { ShowData(dataExample) } }
Operazioni asincrone in Compose
Jetpack Compose ti consente di eseguire operazioni asincrone utilizzando le coroutine all'interno dei tuoi composable.
Per saperne di più, consulta le API LaunchedEffect
, produceState
e rememberCoroutineScope
nella documentazione sugli effetti collaterali.
Navigazione
Il componente Navigation fornisce supporto per le applicazioni Jetpack Compose. Per ulteriori informazioni, consulta Navigazione con Compose e Migrare la navigazione Jetpack a Navigation Compose.
Hilt
Hilt è la soluzione consigliata per l'inserimento delle dipendenze nelle app per Android e funziona perfettamente con Compose.
La funzione viewModel()
menzionata nella sezione ViewModel
utilizza automaticamente il ViewModel creato da Hilt con l'annotazione @HiltViewModel
. Abbiamo fornito la documentazione con informazioni sull'integrazione di ViewModel di Hilt.
@HiltViewModel class MyViewModel @Inject constructor( private val savedStateHandle: SavedStateHandle, private val repository: ExampleRepository ) : ViewModel() { /* ... */ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { /* ... */ }
Impugnatura e navigazione
Hilt si integra anche con la libreria Navigation Compose. Aggiungi le seguenti dipendenze aggiuntive al file Gradle:
Groovy
dependencies { implementation 'androidx.hilt:hilt-navigation-compose:1.2.0' }
Kotlin
dependencies { implementation("androidx.hilt:hilt-navigation-compose:1.2.0") }
Quando utilizzi Navigation Compose, usa sempre la funzione hiltViewModel
composable
per ottenere un'istanza di @HiltViewModel
annotated ViewModel
.
Funziona con frammenti o attività annotati con
@AndroidEntryPoint
.
Ad esempio, se ExampleScreen
è una destinazione in un grafico di navigazione,
chiama hiltViewModel()
per ottenere un'istanza di ExampleViewModel
con ambito
alla destinazione, come mostrato nello snippet di codice seguente:
// import androidx.hilt.navigation.compose.hiltViewModel @Composable fun MyApp() { val navController = rememberNavController() val startRoute = "example" NavHost(navController, startDestination = startRoute) { composable("example") { backStackEntry -> // Creates a ViewModel from the current BackStackEntry // Available in the androidx.hilt:hilt-navigation-compose artifact val viewModel = hiltViewModel<MyViewModel>() MyScreen(viewModel) } /* ... */ } }
Se devi recuperare l'istanza di un ViewModel
con ambito
itinerari di navigazione o grafico
di navigazione, utilizza la funzione componibile hiltViewModel
e passa il backStackEntry
corrispondente come parametro:
// import androidx.hilt.navigation.compose.hiltViewModel // import androidx.navigation.compose.getBackStackEntry @Composable fun MyApp() { val navController = rememberNavController() val startRoute = "example" val innerStartRoute = "exampleWithRoute" NavHost(navController, startDestination = startRoute) { navigation(startDestination = innerStartRoute, route = "Parent") { // ... composable("exampleWithRoute") { backStackEntry -> val parentEntry = remember(backStackEntry) { navController.getBackStackEntry("Parent") } val parentViewModel = hiltViewModel<ParentViewModel>(parentEntry) ExampleWithRouteScreen(parentViewModel) } } } }
Paging
La libreria
Paging
facilita il caricamento graduale dei dati ed è supportata in Compose.
La pagina di rilascio della paginazione contiene informazioni sulla dipendenza paging-compose
aggiuntiva che deve essere aggiunta al progetto e alla relativa versione.
Ecco un esempio delle API Compose della libreria Paging:
@Composable fun MyScreen(flow: Flow<PagingData<String>>) { val lazyPagingItems = flow.collectAsLazyPagingItems() LazyColumn { items( lazyPagingItems.itemCount, key = lazyPagingItems.itemKey { it } ) { index -> val item = lazyPagingItems[index] Text("Item is $item") } } }
Per ulteriori informazioni sull'utilizzo della paginazione in Compose, consulta la documentazione relativa a elenchi e griglie.
Maps
Puoi utilizzare la libreria Maps Compose per fornire Google Maps nella tua app. Ecco un esempio di utilizzo:
@Composable fun MapsExample() { val singapore = LatLng(1.35, 103.87) val cameraPositionState = rememberCameraPositionState { position = CameraPosition.fromLatLngZoom(singapore, 10f) } GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = cameraPositionState ) { Marker( state = remember { MarkerState(position = singapore) }, title = "Singapore", snippet = "Marker in Singapore" ) } }
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Effetti collaterali in Compose
- State e Jetpack Compose
- Salvare lo stato dell'interfaccia utente in Compose