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

Aktivitäten

Wenn Sie „Compose“ in einer Aktivität verwenden möchten, müssen Sie ComponentActivity verwenden. Dies ist eine abgeleitete Klasse von Activity, die die entsprechenden LifecycleOwner und Komponenten für Compose bereitstellt. Außerdem bietet es zusätzliche APIs, die Ihren Code vom Überschreiben von Methoden in Ihrer Aktivitätsklasse entkoppeln. Mit der Funktion Activity Compose lassen sich diese APIs zusammensetzbaren Funktionen zur Verfügung stellen, sodass das Überschreiben von Methoden außerhalb der zusammensetzbaren Funktionen oder das Abrufen einer expliziten Activity-Instanz nicht mehr erforderlich ist. Darüber hinaus sorgen diese APIs dafür, dass sie nur einmal initialisiert werden, die Neuzusammensetzung überdauern und ordnungsgemäß bereinigt werden, wenn die zusammensetzbare Funktion aus der Zusammensetzung entfernt wird.

Aktivitätsergebnis

Mit der rememberLauncherForActivityResult() API können Sie ein Ergebnis aus einer Aktivität in Ihrer zusammensetzbaren Funktion abrufen:

@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 einen einfachen GetContent()-Vertrag. Durch Tippen auf die Schaltfläche wird die Anfrage gestartet. Das nachgestellte Lambda für rememberLauncherForActivityResult() wird aufgerufen, sobald der Nutzer ein Bild ausgewählt hat und zur Startaktivität zurückkehrt. Dadurch wird das ausgewählte Bild mit der Funktion rememberImagePainter() von Coil geladen.

Jede abgeleitete Klasse 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 benutzerdefinierten Verträge erstellen und mit dieser Technik verwenden.

Laufzeitberechtigungen anfordern

Die oben erläuterte Activity Result API und der oben beschriebene rememberLauncherForActivityResult() können verwendet werden, um Laufzeitberechtigungen anzufordern. Dabei werden der RequestPermission-Vertrag für eine einzelne Berechtigung oder der Vertrag RequestMultiplePermissions für mehrere Berechtigungen verwendet.

Mit der Accompanist-Berechtigungsbibliothek lässt sich auch eine Ebene über diesen APIs erstellen, um den aktuell erteilten Status für Berechtigungen dem Status zuzuordnen, den Ihre Compose-UI verwenden kann.

Umgang mit der Zurück-Schaltfläche des Systems

Wenn Sie eine benutzerdefinierte Zurück-Navigation bereitstellen und das Standardverhalten der Zurück-Schaltfläche des Systems in der zusammensetzbaren Funktion überschreiben möchten, kann die zusammensetzbare Funktion eine BackHandler verwenden, um dieses Ereignis abzufangen:

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

Das erste Argument steuert, ob BackHandler derzeit aktiviert ist. Mit diesem Argument können Sie den Handler je nach Status der Komponente vorübergehend deaktivieren. Die nachgestellte Lambda-Funktion wird aufgerufen, wenn der Nutzer ein Systemback-Ereignis auslöst und BackHandler derzeit aktiviert ist.

ViewModel

Wenn Sie die ViewModel-Bibliothek für Architekturkomponenten verwenden, können Sie über jede zusammensetzbare Funktion auf ein ViewModel zugreifen, indem Sie die Funktion viewModel() aufrufen.

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

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

viewModel() gibt ein vorhandenes ViewModel-Objekt zurück oder erstellt eine neue ViewModel im angegebenen Bereich. Die ViewModel wird beibehalten, solange der Bereich aktiv ist. Wenn die zusammensetzbare Funktion beispielsweise in einer Aktivität verwendet wird, gibt viewModel() dieselbe Instanz zurück, bis die Aktivität abgeschlossen 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
) { /* ... */ }

Wenn in Ihrem ViewModel Abhängigkeiten vorhanden sind, verwendet viewModel() einen optionalen ViewModelProvider.Factory als Parameter.

Weitere Informationen zu ViewModel in Compose und zur Verwendung von Instanzen mit der Navigation Compose-Bibliothek oder zu Aktivitäten und Fragmenten 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 werden als Listener registriert und stellen die Werte als State dar. Immer wenn ein neuer Wert ausgegeben wird, setzt „Compose“ die Teile der UI neu zusammen, in denen state.value verwendet wird. In diesem Code wird ShowData beispielsweise jedes Mal neu zusammengesetzt, wenn exampleLiveData einen neuen Wert ausgibt.

// 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 mit Koroutinen in Ihren zusammensetzbaren Funktionen ausführen.

Weitere Informationen findest du in den APIs für LaunchedEffect, produceState und rememberCoroutineScope in der Dokumentation zu Nebeneffekten.

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.

Griff

Hilt ist die empfohlene Lösung für das Einschleusen von Abhängigkeiten in Android-Apps und funktioniert nahtlos mit Compose.

Die im Abschnitt ViewModel erwähnte Funktion viewModel() verwendet automatisch die ViewModel-Funktion, die von Hilt mit der Annotation @HiltViewModel erstellt wird. In der Dokumentation findest du Informationen zur ViewModel-Integration von 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()
) { /* ... */ }

Griff und Navigation

Hilt ist auch in die Navigation Compose-Bibliothek integriert. Fügen Sie Ihrer Gradle-Datei die folgenden zusätzlichen Abhängigkeiten hinzu:

Cool

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

Kotlin

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

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

Wenn ExampleScreen beispielsweise ein Ziel in einer Navigationsgrafik ist, rufen Sie hiltViewModel() auf, um eine Instanz von ExampleViewModel abzurufen, die auf das Ziel beschränkt ist, 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 stattdessen die Instanz eines ViewModel abrufen möchten, der auf Navigationsrouten oder die Navigationsgrafik beschränkt ist, verwenden Sie die zusammensetzbare Funktion hiltViewModel und übergeben Sie den entsprechenden 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)
            }
        }
    }
}

Paging

Die Paging-Bibliothek erleichtert das schrittweise Laden von Daten und wird in Compose unterstützt. Die Releaseseite "Paging" 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 des Seitenumbruchs in „Compose“ finden Sie in der Dokumentation zu Listen und Rastern.

Maps

Sie können die Bibliothek Maps Compose verwenden, um Google Maps in Ihrer App bereitzustellen. Hier ein Anwendungsbeispiel:

@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 = MarkerState(position = singapore),
            title = "Singapore",
            snippet = "Marker in Singapore"
        )
    }
}