Compose und andere Bibliotheken

In „Compose“ können Sie Ihre bevorzugten Bibliotheken verwenden. In diesem Abschnitt wird beschrieben, wie Sie einige der nützlichsten Bibliotheken integrieren.

Aktivität

Wenn Sie „Compose“ in einer Aktivität verwenden möchten, müssen Sie ComponentActivity verwenden, eine Unterklasse von Activity, die die entsprechenden LifecycleOwner- und -Komponenten für „Compose“ bereitstellt. Außerdem bietet es zusätzliche APIs, die Ihren Code entkoppeln Methoden in Ihrer Aktivitätsklasse zu verhindern. Aktivität verfassen diese APIs zusammensetzbaren Funktionen zur Verfügung stellen, sodass das Überschreiben von Methoden außerhalb Ihres zusammensetzbare Funktionen oder das Abrufen einer expliziten Activity-Instanz sind nicht mehr erforderlich. Darüber hinaus stellen diese APIs sicher, dass sie nur einmal initialisiert werden, Zusammensetzung und saubere Inhalte entfernen, wenn die zusammensetzbare Funktion aus der Zusammensetzung.

Aktivitätsergebnis

Die rememberLauncherForActivityResult() API ermöglicht Ihnen Folgendes: Ergebnis aus einer Aktivität abrufen in der zusammensetzbaren Funktion:

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

Dieses Beispiel zeigt ein einfaches GetContent() Vertrag. Durch Tippen auf die Schaltfläche wird die Anfrage gestartet. Das abschließende Lambda für rememberLauncherForActivityResult() wird aufgerufen, sobald der Nutzer ein Bild ausgewählt und zur Startaktivität zurückgekehrt ist. Dadurch wird das ausgewählte Bild mit dem rememberImagePainter() von Coil geladen .

Jede Unterklasse von ActivityResultContract kann als erstes Argument für rememberLauncherForActivityResult() verwendet werden. Das bedeutet, dass Sie mit dieser Technik Inhalte aus dem Framework und in anderen gängigen Mustern anfordern können. Sie können auch Ihre eigenen kundenspezifischen Verträgen und verwenden Sie mit dieser Technik.

Laufzeitberechtigungen anfordern

Dieselbe Activity Result API und rememberLauncherForActivityResult() wie oben beschrieben, können Laufzeitberechtigungen anfordern mithilfe der RequestPermission für eine einzige Genehmigung oder RequestMultiplePermissions für mehrere Berechtigungen.

Die Accompanist Permissions Library kann auch als Schicht über diesen APIs verwendet werden, um den aktuellen gewährten Status für Berechtigungen in einen Status abzubilden, der von Ihrer Compose-Benutzeroberfläche verwendet werden kann.

Zurück-Schaltfläche des Systems

Um eine benutzerdefinierte Rückwärtsnavigation bereitzustellen und das Standardverhalten der Zurück-Schaltfläche des Systems zusammensetzbar ist, kann Ihre zusammensetzbare Funktion BackHandler um dieses Ereignis abzufangen:

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

Mit dem ersten Argument wird festgelegt, ob BackHandler derzeit aktiviert ist. Mit diesem Argument können Sie den Handler je nach Status der Komponente vorübergehend deaktivieren. Das nachgestellte Lambda wird aufgerufen, wenn die ein System-Back-Ereignis auslöst und der BackHandler ist derzeit aktiviert.

ViewModel

Wenn Sie die Architecture Components ViewModel-Bibliothek verwenden, können Sie über die Funktion viewModel() auf eine ViewModel aus jeder Composeable-Komponente zugreifen. Fügen Sie Ihrer Gradle-Datei die folgende Abhängigkeit hinzu:

Groovy

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

Kotlin

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

Anschließend können Sie die Funktion viewModel() in Ihrem Code verwenden.

class MyViewModel : ViewModel() { /*...*/ }

// import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) {
    // use viewModel here
}

viewModel() gibt eine vorhandene ViewModel zurück oder erstellt eine neue. Standardmäßig ist der zurückgegebene ViewModel auf die umschließende Aktivität, das Fragment oder das Navigationsziel beschränkt und wird so lange beibehalten, wie der Bereich aktiv ist.

Wenn das Composeable beispielsweise in einer Aktivität verwendet wird, gibt viewModel() dieselbe Instanz zurück, bis die Aktivität beendet oder der Prozess beendet wird.

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

Nutzungsrichtlinien

Normalerweise greifen Sie auf ViewModel Instanzen auf Bildschirmebene zu zusammensetzbar, also nahe an einer zusammensetzbaren Stammfunktion, die aus einer Aktivität aufgerufen wird, Fragment oder Ziel eines Navigationsdiagramms. Grund: ViewModel sind standardmäßig diesen Objekten auf Bildschirmebene zugeordnet. Weitere Informationen zum Lebenszyklus und Umfang von ViewModel

Vermeiden Sie es, ViewModel-Instanzen an andere Composeables weiterzugeben, da dies die Tests dieser Composeables erschweren und Vorschauen beeinträchtigen kann. Stattdessen werden nur die Daten und Funktionen, die sie als Parameter benötigen.

Sie können ViewModel-Instanzen verwenden, um den Status für Composables auf Unterbildschirmebene zu verwalten. Beachten Sie jedoch den Lebenszyklus und den Umfang von ViewModel. Wenn das composable in sich geschlossen ist, können Sie Hilt verwenden, um die ViewModel einzuschleusen, damit Sie keine Abhängigkeiten von übergeordneten composables übergeben müssen.

Wenn Ihre ViewModel Abhängigkeiten hat, nimmt viewModel() einen optionalen Parameter ViewModelProvider.Factory an.

Weitere Informationen zu ViewModel in Compose und zur Verwendung von Instanzen „Navigation Compose-Bibliothek“ oder Aktivitäten und Fragmente Weitere Informationen finden Sie in der Interoperabilitätsdokumentation.

Datenstreams

Compose enthält Erweiterungen für die beliebtesten streambasierten Android-Lösungen. Jede dieser Erweiterungen wird von einem anderen Artefakt bereitgestellt:

Diese Artefakte registrieren sich als Listener und stellen die Werte als State dar. Wenn ein neuer Wert ausgegeben wird, setzt „Compose“ die Teile der UI neu zusammen, in denen sich state.value befindet verwendet. In diesem Code wird ShowData beispielsweise jedes Mal neu zusammengesetzt. „exampleLiveData“ gibt einen neuen Wert aus.

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

Asynchrone Vorgänge in „Compose“

Mit Jetpack Compose können Sie asynchrone Vorgänge mithilfe von Tasks aus Ihren Composables ausführen.

Weitere Informationen finden Sie in der Dokumentation zu Nebenwirkungen zu den APIs LaunchedEffect, produceState und rememberCoroutineScope.

Die Navigationskomponente bietet Unterstützung für Jetpack Compose-Anwendungen. Weitere Informationen finden Sie unter Mit Compose navigieren und Jetpack Navigation zu Navigation Compose migrieren.

Hilt

Hilt ist die empfohlene Lösung für das Einschleusen von Abhängigkeiten in Android-Apps. mit der Funktion „Schreiben“.

Die im Abschnitt ViewModel erwähnte viewModel()-Funktion verwendet automatisch das ViewModel, das Hilt mit der @HiltViewModel-Anmerkung erstellt. Wir haben eine Dokumentation mit Informationen zur ViewModel-Integration von Hilt bereitgestellt.

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

Hilt und Navigation

Hilt lässt sich auch in die Navigation Compose-Bibliothek einbinden. Folgendes hinzufügen zusätzliche Abhängigkeiten zu Ihrer Gradle-Datei hinzufügen:

Cool

dependencies {
    implementation 'androidx.hilt:hilt-navigation-compose:1.2.0'
}

Kotlin

dependencies {
    implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
}

Wenn Sie „Navigation Compose“ verwenden, verwenden Sie immer die zusammensetzbare Funktion hiltViewModel , um eine Instanz der mit @HiltViewModel annotierten ViewModel abzurufen. Das funktioniert mit Fragmenten oder Aktivitäten, die mit @AndroidEntryPoint annotiert sind.

Beispiel: Wenn ExampleScreen ein Ziel in einer Navigationsgrafik ist, hiltViewModel() aufrufen, um eine Instanz des Bereichs ExampleViewModel abzurufen an das Ziel, wie im folgenden Code-Snippet gezeigt:

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

Wenn Sie die Instanz eines ViewModel mit dem Gültigkeitsbereich Navigationsrouten oder Navigationsgraph abrufen möchten, verwenden Sie stattdessen die zusammensetzbare Funktion hiltViewModel und übergeben Sie die entsprechende backStackEntry als Parameter:

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

Auslagerung

Mit der Paging-Bibliothek können Sie Daten nach und nach laden. Sie wird in Compose unterstützt. Die Seite zum Release der Seitenleiste enthält Informationen zur zusätzlichen paging-compose-Abhängigkeit, die dem Projekt und seiner Version hinzugefügt werden muss.

Hier ein Beispiel für die Compose APIs der Paging-Bibliothek:

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

Weitere Informationen zur Verwendung der Paginierung in Compose finden Sie in der Dokumentation zu Listen und Rastern.

Maps

Mit der Maps Compose-Bibliothek können Sie Google Maps in Ihrer App verwenden. Hier ein Beispiel für die Verwendung:

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