W Compose możesz używać ulubionych bibliotek. W tej sekcji opisano, jak włączyć kilka najbardziej przydatnych bibliotek.
Aktywność
Aby używać Compose w aktywności, musisz użyć ComponentActivity
, podklasy Activity
, która udostępnia odpowiednie LifecycleOwner
i komponenty dla Compose. Zawiera też dodatkowe interfejsy API, które oddzielają 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ą ponowne komponowanie i są prawidłowo czyszczone, jeśli funkcja kompozycyjna zostanie usunięta z kompozycji.
Wynik aktywności
Interfejs API rememberLauncherForActivityResult()
umożliwia uzyskanie wyniku działania w funkcji kompozycyjnej:
@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 przedstawia prostą umowę
GetContent()
. Kliknięcie przycisku powoduje wysłanie prośby. Funkcja lambda końcowa dla
rememberLauncherForActivityResult()
jest wywoływana, gdy użytkownik wybierze obraz i wróci do aktywności uruchamiającej.
Spowoduje to wczytanie wybranego obrazu za pomocą funkcji rememberImagePainter()
biblioteki Coil.
Jako pierwszy argument funkcji rememberLauncherForActivityResult()
można użyć dowolnej podklasy ActivityResultContract
.
Oznacza to, że możesz używać tej techniki do wysyłania do platformy żądań dotyczących treści i innych typowych wzorców. Możesz też tworzyć własne umowy niestandardowe i używać ich w tej technice.
Wysyłanie prośby o uprawnienia w czasie działania
Ten sam interfejs Activity Result API i rememberLauncherForActivityResult()
, o którym pisaliśmy powyżej, może służyć do wysyłania próśb o uprawnienia w czasie działania za pomocą kontraktu RequestPermission
dla pojedynczego uprawnienia lub kontraktu RequestMultiplePermissions
dla wielu uprawnień.
Biblioteka uprawnień towarzyszących może być też używana jako warstwa nad tymi interfejsami API do mapowania bieżącego stanu przyznanych uprawnień na stan, którego może używać interfejs Compose.
Obsługa systemowego przycisku Wstecz
Aby zapewnić niestandardową nawigację wstecz i zastąpić domyślne działanie systemowego przycisku Wstecz w kompozycji, możesz użyć BackHandler
, aby przechwycić to zdarzenie:
var backHandlingEnabled by remember { mutableStateOf(true) } BackHandler(backHandlingEnabled) { // Handle back press }
Pierwszy argument określa, czy element BackHandler
jest obecnie włączony. Możesz go użyć, aby tymczasowo wyłączyć moduł obsługi na podstawie stanu komponentu. Funkcja lambda na końcu zostanie wywołana, jeśli użytkownik wywoła zdarzenie systemowe „wstecz”, a BackHandler
jest obecnie włączone.
ViewModel
Jeśli używasz biblioteki Architecture Components ViewModel, możesz uzyskać dostęp do ViewModel
z dowolnego komponentu kompozycyjnego, wywołując funkcję viewModel()
. Dodaj do pliku Gradle tę zależność:
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 kodzie funkcji viewModel()
.
class MyViewModel : ViewModel() { /*...*/ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { // use viewModel here }
viewModel()
zwraca istniejący ViewModel
lub tworzy nowy. Domyślnie zwrócony obiekt ViewModel
jest ograniczony do otaczającego działania, fragmentu lub miejsca docelowego nawigacji i jest przechowywany tak długo, jak długo jest aktywny zakres.
Jeśli np. funkcja kompozycyjna jest używana w aktywności, viewModel()
zwraca tę samą instancję do momentu 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
w komponentach na poziomie ekranu, czyli w pobliżu komponentu głównego wywoływanego z aktywności, fragmentu lub miejsca docelowego wykresu nawigacji. Dzieje się tak, ponieważ ViewModel
s
są domyślnie ograniczone do obiektów na poziomie ekranu. Więcej informacji o cyklu życia i zakresie ViewModel
znajdziesz tutaj.
Staraj się nie przekazywać instancji ViewModel
do innych funkcji kompozycyjnych, ponieważ może to utrudnić testowanie tych funkcji i spowodować nieprawidłowe działanie podglądów. Zamiast tego przekazuj tylko dane i funkcje, których potrzebują, jako parametry.
Możesz używać instancji ViewModel
do zarządzania stanem w przypadku komponentów kompozycyjnych na poziomie podrzędnego ekranu, ale pamiętaj o cyklu życia i zakresie ViewModel
. Jeśli funkcja kompozycyjna jest samodzielna, możesz użyć Hilta do wstrzykiwania ViewModel
, aby uniknąć przekazywania zależności z funkcji kompozycyjnych wyższego rzędu.
Jeśli ViewModel
ma zależności, viewModel()
przyjmuje opcjonalny parametr
ViewModelProvider.Factory
.
Więcej informacji o ViewModel
w Compose i o tym, jak używane są instancje w bibliotece Navigation Compose, a także o aktywnościach i fragmentach znajdziesz w dokumentacji dotyczącej interoperacyjności.
Strumienie danych
Compose ma rozszerzenia do najpopularniejszych rozwiązań opartych na strumieniach w Androidzie. Każde z tych rozszerzeń jest dostarczane przez inny artefakt:
LiveData.observeAsState()
– zawarte w artefakcieandroidx.compose.runtime:runtime-livedata:$composeVersion
.Flow.collectAsState()
nie wymaga dodatkowych zależności.Observable.subscribeAsState()
zawarty w artefakcieandroidx.compose.runtime:runtime-rxjava2:$composeVersion
lubandroidx.compose.runtime:runtime-rxjava3:$composeVersion
.
Te artefakty rejestrują się jako odbiorcy i przedstawiają wartości jako State
. Za każdym razem, gdy zostanie wyemitowana nowa wartość, Compose ponownie skomponuje te części interfejsu, w których używana jest ta state.value
. Na przykład w tym kodzie ShowData
jest ponownie komponowany za każdym razem, gdy exampleLiveData
emituje 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 Compose
Jetpack Compose umożliwia wykonywanie operacji asynchronicznych za pomocą korutyn w funkcjach kompozycyjnych.
Więcej informacji o interfejsach API LaunchedEffect
, produceState
i rememberCoroutineScope
znajdziesz w dokumentacji dotyczącej efektów ubocznych.
Nawigacja
Komponent nawigacji obsługuje aplikacje Jetpack Compose. Więcej informacji znajdziesz w artykułach Nawigacja za pomocą Compose i Migracja z Jetpack Navigation na Navigation Compose.
Hilt
Hilt to zalecane rozwiązanie do wstrzykiwania zależności w aplikacjach na Androida, które bezproblemowo współpracuje z Compose.
Funkcja viewModel()
wspomniana w sekcji ViewModel automatycznie używa obiektu ViewModel, który Hilt tworzy 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 jest też zintegrowany 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 Navigation Compose zawsze używaj funkcji hiltViewModel
composable
do uzyskiwania instancji @HiltViewModel
z adnotacjami ViewModel
.
Działa to w przypadku fragmentów lub aktywności, które są oznaczone adnotacjami @AndroidEntryPoint
.
Jeśli na przykład ExampleScreen
jest miejscem docelowym na wykresie nawigacji, wywołaj hiltViewModel()
, aby uzyskać instancję ExampleViewModel
w zakresie miejsca docelowego, jak pokazano we fragmencie kodu poniżej:
// 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 zamiast tego chcesz pobrać instancję ViewModel
w zakresie tras nawigacji lub grafu nawigacji, użyj funkcji kompozycyjnej hiltViewModel
i przekaż odpowiedni element backStackEntry
jako parametr:
// 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
Biblioteka Paging ułatwia stopniowe wczytywanie danych i jest obsługiwana w Compose.
Na stronie wersji Paging znajdziesz informacje o dodatkowej zależności paging-compose
, którą należy dodać do projektu, oraz jej wersji.
Oto przykład interfejsów API 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 biblioteki Paging w Compose znajdziesz w dokumentacji dotyczącej list i siatek.
Mapy
Aby udostępniać Mapy Google w aplikacji, możesz użyć biblioteki Maps Compose. 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" ) } }
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy JavaScript jest wyłączony.
- Efekty uboczne w Compose
- Stan i Jetpack Compose
- Zapisywanie stanu interfejsu w Compose