Scrittura e altre librerie

Puoi utilizzare le tue librerie preferite in Scrivi. Questa sezione descrive come incorporare alcune delle librerie più utili.

Attività

Per utilizzare Compose in un'attività, devi usare ComponentActivity, una sottoclasse di Activity che fornisce i valori LifecycleOwner e componenti in Compose. Fornisce inoltre API aggiuntive che disaccoppiano il codice dai metodi di override nella tua classe di attività. Scrittura attività espone queste API agli elementi componibili, in modo che l'override dei metodi al di fuori del componibili o il recupero di un'istanza Activity esplicita non è più necessario. Inoltre, queste API assicurano di essere inizializzate una sola volta, di sopravvivere alla ricompozione e di essere ripulite correttamente se il composable viene rimosso dalla composizione.

Risultato attività

La rememberLauncherForActivityResult() API ti consente di ottenere un risultato da un'attività nel tuo 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 contratto GetContent() semplice. Toccando il pulsante viene avviata la richiesta. La lambda finale per rememberLauncherForActivityResult() viene invocata quando l'utente seleziona un'immagine e torna all'attività di lancio. L'immagine selezionata viene caricata utilizzando rememberImagePainter() di Coil personalizzata.

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 di autorizzazioni di runtime

La stessa API Activity Result e rememberLauncherForActivityResult() spiegate sopra possono essere utilizzate per richiedere le autorizzazioni di runtime utilizzando il contratto RequestPermission per una singola autorizzazione o RequestMultiplePermissions per più autorizzazioni.

La Libreria delle autorizzazioni di partecipazione puoi anche utilizzare un livello superiore a queste API per mappare lo stato concesso attuale le autorizzazioni nello stato utilizzabile dall'interfaccia utente di Compose.

Gestione del pulsante Indietro del sistema

Per fornire la navigazione a ritroso personalizzata e sostituire il comportamento predefinito del pulsante Indietro di sistema dall'interno del composable, il composable può utilizzare un BackHandler per intercettare l'evento:

var backHandlingEnabled by remember { mutableStateOf(true) }
BackHandler(backHandlingEnabled) {
    // Handle back press
}

Il primo argomento controlla se il gestore BackHandler è attualmente attivo. Puoi utilizzare questo argomento per disattivare temporaneamente il gestore in base allo stato del componente. La lambda finale verrà invocata se l'utente attiva un evento di ritorno di sistema e BackHandler è attualmente attivo.

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 file Gradle:

Groovy

dependencies {
    implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5'
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5")
}

A questo punto, puoi utilizzare la funzione viewModel() nel 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, ViewModel restituito è limitato all'attività, al frammento o alla destinazione di navigazione che lo contiene e viene mantenuto attivo finché l'ambito è attivo.

Ad esempio, se il componibile viene utilizzato in un'attività, viewModel() restituisce il la stessa istanza fino al termine dell'attività o fino all'interruzione del processo.

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 a ViewModel istanze a livello di schermo componibili, cioè vicini a un componibile radice chiamato da un'attività, frammento o la destinazione di un grafico di navigazione. Questo perché ViewModels sono, per impostazione predefinita, limitati a questi oggetti a livello di schermata. Scopri di più sul ciclo di vita e sull'ambito di un ViewModel qui.

Cerca di non trascurare ViewModel di istanze ad altri componibili, in quanto ciò può rendere tali elementi componibili più difficili da testare e possono danneggiare anteprime. Passa invece solo i dati e le funzioni di cui hanno bisogno come parametri.

Puoi utilizzare ViewModel istanze per gestisci lo stato per gli elementi componibili a livello di schermo secondario, tuttavia, tieni presente di ViewModel ciclo di vita e ambito. Se il composable è autonomo, ti consigliamo di utilizzare Hilt per iniettare ViewModel per evitare di dover passare le dipendenze dai composable di primo livello.

Se ViewModel ha dipendenze, viewModel() accetta un parametro facoltativo ViewModelProvider.Factory.

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à.

Flussi di dati

Compose è dotato di estensioni per le soluzioni basate su stream più diffuse di Android. Ognuna di queste estensioni è fornita da un elemento diverso:

Questi elementi vengono registrati come ascoltatori e rappresentano i valori come State. Ogni volta che un nuovo valore viene emesso, Compose ricompone le parti della UI in cui viene emesso state.value in uso. Ad esempio, in questo codice, ShowData si ricomponie ogni volta cheexampleLiveData 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 componibili.

Visualizza le API LaunchedEffect, produceState e rememberCoroutineScope in la documentazione relativa agli effetti collaterali per ulteriori informazioni informazioni.

Il componente Navigazione fornisce supporto per le applicazioni Jetpack Compose. Per ulteriori informazioni, consulta Navigare con Compose e Eseguire la migrazione di Jetpack Navigation a Navigation Compose.

Elsa

Hilt è la soluzione consigliata per l'iniezione di 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 @HiltViewModel annotazione. Abbiamo fornito la documentazione con informazioni sul ViewModel di Hilt integrazione.

@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()
) { /* ... */ }

Escursionismo e navigazione

Hilt si integra anche con la libreria Navigation Compose. Aggiungi quanto segue ulteriori dipendenze al tuo 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 composable hiltViewModel per ottenere un'istanza del tuo @HiltViewModel annotato ViewModel. Questa operazione è valida per i frammenti o le attività annotati con @AndroidEntryPoint.

Ad esempio, se ExampleScreen è una destinazione in un grafico di navigazione, chiama hiltViewModel() per ottenere un'istanza con ambito ExampleViewModel alla destinazione, come mostrato nello snippet di codice riportato di seguito:

// 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 invece devi recuperare l'istanza di un ViewModel limitata ai percorsi di navigazione o al grafo di navigazione, utilizza la funzione componibile hiltViewModel e passa il corrispondente backStackEntry 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 di Paginazione consente di caricare più facilmente i dati gradualmente ed è supportata in Componi. La pagina di release 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 di 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")
        }
    }
}

Consulta la documentazione su elenchi e griglie per saperne di più sull'utilizzo della paginazione in Compose.

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