Tworzenie i inne biblioteki

W sekcji „Tworzenie” możesz korzystać z ulubionych bibliotek. Z tej sekcji dowiesz się, jak włączyć kilka najprzydatniejszych bibliotek.

Aktywność

Aby użyć Compose w aktywności, musisz użyć klasy ComponentActivity, która jest podklasą klasy Activity i zawiera odpowiednie komponenty LifecycleOwner do Compose. Udostępnia też dodatkowe interfejsy API, które odłączają kod od zastępowania metod w klasie aktywności. Activity Compose udostępnia te interfejsy API komponentom, dzięki czemu nie trzeba już zastępować metod poza komponentami ani pobierać jawnej instancji Activity. Ponadto te interfejsy API zapewniają, że są inicjowane tylko raz, przetrwają rekompozycję i zostają prawidłowo usunięte, jeśli kompozyt został usunięty z kompozycji.

Wynik aktywności

Interfejs API rememberLauncherForActivityResult() umożliwia uzyskanie wyniku z działalności w komponowalnym:

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

Ten przykład pokazuje prosty GetContent()kontrakt. Kliknięcie przycisku spowoduje uruchomienie prośby. Lambda końcowa dla rememberLauncherForActivityResult() jest wywoływana, gdy użytkownik wybierze obraz i wróci do aktywności uruchamiającej. Spowoduje to załadowanie wybranego obrazu za pomocą funkcji rememberImagePainter() Coil.

Jako pierwszy argument funkcji rememberLauncherForActivityResult() można użyć dowolnej podklasy typu ActivityResultContract. Oznacza to, że możesz użyć tej techniki, aby poprosić o treści z ramy, a także w innych typowych wzorach. Możesz też tworzyć własne kontrakty niestandardowe i stosować je za pomocą tej metody.

Wysyłanie prośby o uprawnienia w czasie działania

Tego samego interfejsu Activity Result API i rememberLauncherForActivityResult(), o których mowa powyżej, można używać do wysyłania żądań uprawnień na czas działania, korzystając z RequestPermissionuprawnień dla pojedynczego uprawnienia lub RequestMultiplePermissionsuprawnień dla wielu uprawnień.

Bibliotekę Accompanist Permissions można też używać jako warstwy nad tymi interfejsami API, aby mapować bieżący stan uprawnień na stan, którego może używać interfejs użytkownika Compose.

Obsługa systemowego przycisku Wstecz

Aby zapewnić niestandardową nawigację wstecz i zastąpić domyślne zachowanie przycisku Wstecz w systemie, komponent może użyć elementu BackHandler, aby przechwycić to zdarzenie:

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

Pierwszy argument określa, czy moduł BackHandler jest obecnie włączony. Możesz użyć tego argumentu, aby tymczasowo wyłączyć moduł obsługi na podstawie stanu komponentu. Lambda końcowa zostanie wywołana, jeśli użytkownik wywoła zdarzenie systemowe, a BackHandler jest obecnie włączone.

ViewModel

Jeśli używasz biblioteki ViewModel Komponenty architektury, możesz uzyskać dostęp do modelu ViewModel z dowolnego elementu kompozycyjnego, wywołując funkcję viewModel(). Dodaj do pliku Gradle te zależności:

Groovy

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

Kotlin

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

Następnie możesz użyć w kodze funkcji viewModel().

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

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

viewModel() zwraca istniejący element ViewModel lub tworzy nowy. Domyślnie zwracany element ViewModel jest ograniczony do obejmującej go aktywności, fragmentu lub miejsca docelowego nawigacji i jest przechowywany tak długo, jak długo istnieje zakres.

Jeśli na przykład kompozyt jest używany w aktywności, viewModel() zwraca tę samą instancję do czasu zakończenia aktywności lub zakończenia procesu.

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

Wytyczne dotyczące użytkowania

Zwykle uzyskujesz dostęp do instancji ViewModel na poziomie funkcji kompozycyjnych na poziomie ekranu, czyli w pobliżu głównego elementu kompozycyjnego wywoływanego z działania, fragmentu lub miejsca docelowego grafu nawigacji. Dzieje się tak, ponieważ ViewModelsą domyślnie ograniczone do tych obiektów na poziomie ekranu. Dowiedz się więcej o cyklu życia i zakresie usługi ViewModel.

Staraj się nie przekazywać instancji ViewModel innym elementom składanym, ponieważ może to utrudnić ich testowanie i spowodować problemy z podglądem. Zamiast tego przekazuj w postaci parametrów tylko potrzebne dane i funkcje.

Możesz używać instancji ViewModel do zarządzania stanem elementów kompozycyjnych na poziomie ekranu podrzędnego, ale pamiętaj o cyklu życia i zakresie elementu ViewModel. Jeśli funkcja kompozycyjna jest autonomiczna, możesz użyć Hilt, aby wstawić ViewModel. Pozwoli to uniknąć przekazywania zależności od nadrzędnych funkcji kompozycyjnych.

Jeśli funkcja ViewModel ma zależności, funkcja viewModel() przyjmuje opcjonalny parametr ViewModelProvider.Factory.

Więcej informacji o komponencie ViewModel w Compose oraz o tym, jak używać instancji z biblioteką Compose nawigacji lub aktywności i fragmentów znajdziesz w dokumentacji dotyczącej interoperacyjności.

strumienie danych,

Usługa Compose zawiera rozszerzenia do najpopularniejszych rozwiązań na Androida korzystających ze strumieniowania. Każde z tych rozszerzeń jest dostarczane w ramach innego artefaktu:

Te artefakty są rejestrowane jako detektor i reprezentują wartości jako State. Za każdym razem, gdy zostanie wyemitowana nowa wartość, Compose ponownie skompiluje te części interfejsu, w których używana jest zmienna state.value. W tym kodzie na przykład ShowData tworzy nową wartość za każdym razem, gdy exampleLiveData generuje nową wartość.

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

Operacje asynchroniczne w funkcji tworzenia wiadomości

Jetpack Compose umożliwia wykonywanie operacji asynchronicznych za pomocą współrzędnych z poziomu kompozytora.

Więcej informacji znajdziesz w dokumentacji interfejsów API LaunchedEffect, produceStaterememberCoroutineScopedokumentacji poświęconej skutkom ubocznym.

Komponent Nawigacja zapewnia obsługę aplikacji Jetpack Compose. Więcej informacji znajdziesz w artykule Przechodzenie między elementami za pomocą ComposePrzenoszenie nawigacji Jetpacka do Compose.

Hilt

Hilt to zalecane rozwiązanie do wstrzykiwania zależności w aplikacjach na Androida. Działa ono bezproblemowo z Compose.

Funkcja viewModel() wymieniona w sekcji ViewModel automatycznie używa ViewModel utworzonego przez Hilt za pomocą adnotacji @HiltViewModel. Udostępniliśmy dokumentację z informacjami o integracji Hilt z ViewModel.

@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 i Nawigacja

Hilt integruje się też z biblioteką Navigation Compose. Dodaj do pliku Gradle te dodatkowe zależności:

Groovy

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

Kotlin

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

Podczas korzystania z komponentu Nawigacja zawsze używaj funkcji hiltViewModel, aby uzyskać instancję @HiltViewModel z annotacjami ViewModel. Działa to we fragmentach lub działaniach oznaczonych adnotacją @AndroidEntryPoint.

Jeśli na przykład ExampleScreen jest celem w grafie nawigacji, wywołaj funkcję hiltViewModel(), aby uzyskać instancję ExampleViewModel ograniczoną do tego celu, jak pokazano w tym fragmencie kodu:

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

Jeśli chcesz zamiast tego pobrać instancję funkcji ViewModel ograniczoną do tras nawigacyjnych lub grafu nawigacyjnego, użyj funkcji składanej hiltViewModel i przekaż jako parametr odpowiednią funkcję backStackEntry:

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

Strona

Biblioteka Paging ułatwia stopniowe wczytywanie danych i jest obsługiwana w Compose. Strona wersji zawiera informacje o dodatkowej zależności paging-compose, którą należy dodać do projektu i jego wersji.

Oto przykład interfejsów Compose biblioteki 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")
        }
    }
}

Więcej informacji o używaniu stronicowania w tworzeniu wiadomości znajdziesz w dokumentacji list i siatek.

Mapy

Możesz użyć biblioteki Maps Compose, aby udostępnić Mapy Google w swojej aplikacji. Oto przykład użycia:

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