Compose und andere Bibliotheken

Sie können in der Funktion „Compose“ auf Ihre bevorzugten Bibliotheken zugreifen. In diesem Abschnitt wird beschrieben, wie Sie einige der nützlichsten Bibliotheken einbinden.

Aktivitäten

Wenn Sie die Funktion „Compose“ in einer Aktivität verwenden möchten, müssen Sie ComponentActivity verwenden. Diese abgeleitete Klasse von Activity stellt die entsprechende LifecycleOwner und Komponenten zum Schreiben bereit. Außerdem bietet es zusätzliche APIs, die Ihren Code vom Überschreiben von Methoden in Ihrer Aktivitätsklasse entkoppeln. Mit Activity Compose werden diese APIs für zusammensetzbare Funktionen zur Verfügung gestellt. Das Überschreiben von Methoden außerhalb Ihrer zusammensetzbaren Funktionen oder das Abrufen einer expliziten Activity-Instanz ist dann nicht mehr erforderlich. Außerdem sorgen diese APIs dafür, dass sie nur einmal initialisiert werden, die Neuzusammensetzung bestehen 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. Wenn Sie auf die Schaltfläche tippen, wird die Anfrage gestartet. Die nachgestellte Lambda-Funktion für rememberLauncherForActivityResult() wird aufgerufen, sobald der Nutzer ein Image 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 dieses Verfahren verwenden können, um Inhalte aus dem Framework und in anderen gängigen Mustern anzufordern. Sie können auch eigene benutzerdefinierte Verträge erstellen und mit diesem Verfahren verwenden.

Laufzeitberechtigungen anfordern

Die Activity Result API und die oben erläuterte rememberLauncherForActivityResult() können verwendet werden, um Laufzeitberechtigungen anzufordern. Verwenden Sie dazu den RequestPermission-Vertrag für eine einzelne Berechtigung oder einen RequestMultiplePermissions-Vertrag für mehrere Berechtigungen.

Die Bibliothek für Berechtigungen kann auch in einer Ebene über diesen APIs verwendet werden, um den aktuell gewährten Berechtigungsstatus dem Status zuzuordnen, den die Benutzeroberfläche für die Erstellung verwenden kann.

Zurück-Taste des Systems bedienen

Wenn Sie benutzerdefinierte Zurück-Navigation bereitstellen und das Standardverhalten der Systemschaltfläche „Zurück“ in Ihrer zusammensetzbaren Funktion überschreiben möchten, kann die zusammensetzbare Funktion ein BackHandler-Ereignis zum Abfangen dieses Ereignisses verwenden:

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 Ihrer Komponente vorübergehend deaktivieren. Die nachgestellte Lambda-Funktion wird aufgerufen, wenn der Nutzer ein Systemrückereignis auslöst und BackHandler derzeit aktiviert ist.

ViewModel

Wenn Sie die ViewModel-Bibliothek für Architekturkomponenten verwenden, können Sie über die Funktion viewModel() aus jeder zusammensetzbaren Funktion auf eine ViewModel zugreifen.

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

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

viewModel() gibt ein vorhandenes ViewModel-Element zurück oder erstellt ein neues im angegebenen Bereich. 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 ist.

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 Ihr ViewModel Abhängigkeiten hat, verwendet viewModel() einen optionalen ViewModelProvider.Factory als Parameter.

Weitere Informationen zu ViewModel in Compose und zur Verwendung von Instanzen mit der Navigation Compose-Bibliothek sowie zu Aktivitäten und Fragmenten finden Sie in den Interoperabilitätsdokumenten.

Datenstreams

Compose enthält Erweiterungen für die beliebtesten streambasierten Lösungen von Android. 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, werden in der Funktion „Compose“ die Teile der UI neu zusammengesetzt, in denen dieser state.value verwendet wird. In diesem Code wird beispielsweise ShowData 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 mithilfe von Koroutinen innerhalb Ihrer zusammensetzbaren Funktionen ausführen.

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

Die Navigationskomponente unterstützt 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 die Abhängigkeitsinjektion in Android-Apps und funktioniert problemlos mit Compose.

Die im Abschnitt „ViewModel“ erwähnte Funktion viewModel() verwendet automatisch das ViewModel, das von Hilt mit der Annotation @HiltViewModel erstellt wird. Eine Dokumentation mit Informationen zur ViewModel-Integration in Hilt findest du hier.

@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 lässt sich auch in die Bibliothek „Navigation Compose“ einbinden. Fügen Sie der Gradle-Datei die folgenden zusätzlichen Abhängigkeiten hinzu:

Groovig

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

Kotlin

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

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

Wenn beispielsweise ExampleScreen ein Ziel in einer Navigationsgrafik ist, rufen Sie hiltViewModel() auf, um eine Instanz von ExampleViewModel für das Ziel abzurufen, 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üssen, der auf Navigationsrouten oder das Navigationsdiagramm 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)
            }
        }
    }
}

Seitenumbruch

Mit der Paging-Bibliothek können Sie Daten einfacher schrittweise laden. Sie wird in Compose unterstützt. Die Seite für den Release-Paging enthält Informationen über die zusätzliche paging-compose-Abhängigkeit, die dem Projekt und dessen 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 Maps Compose-Bibliothek 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"
        )
    }
}