W Compose możesz używać swoich 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 komponenty LifecycleOwner i komponenty do Compose. Zapewnia też dodatkowe interfejsy API, które oddzielają kod od metod zastępowania w klasie aktywności.
Activity Compose udostępnia te interfejsy API elementom kompozycyjnym, dzięki czemu nie trzeba już zastępować metod poza elementami kompozycyjnymi ani pobierać jawnej instancji Activity.
Ponadto te interfejsy API zapewniają, że są inicjowane tylko raz, przetrwają rekompozycję i są prawidłowo czyszczone, jeśli element kompozycyjny zostanie usunięty z kompozycji.
Wynik aktywności
Interfejs API rememberLauncherForActivityResult() umożliwia uzyskanie wyniku z aktywności 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 pokazuje prostą umowę GetContent(). Kliknięcie przycisku powoduje wysłanie prośby. Końcowa funkcja lambda dla rememberLauncherForActivityResult() jest wywoływana, gdy użytkownik wybierze obraz i powróci do aktywności uruchamiającej.
Spowoduje to wczytanie wybranego obrazu za pomocą funkcji rememberImagePainter() biblioteki Coil.
Dowolna podklasa ActivityResultContract może być używana jako pierwszy argument rememberLauncherForActivityResult().
Oznacza to, że możesz użyć tej techniki, aby poprosić o treści z platformy i w innych typowych wzorcach. Możesz też tworzyć własne umowy niestandardowe i używać ich w ramach tej techniki.
Wysyłanie prośby o uprawnienia w czasie działania
Opisany powyżej interfejs Activity Result API i rememberLauncherForActivityResult() można wykorzystać do żądania uprawnień w czasie działania aplikacji za pomocą kontraktu RequestPermission w przypadku pojedynczego uprawnienia lub kontraktu RequestMultiplePermissions w przypadku wielu uprawnień.
Biblioteka uprawnień Accompanist 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ć niestandardowe przechodzenie wstecz i zastąpić działanie domyślne systemowego przycisku Wstecz w funkcji kompozycyjnej, funkcja ta może używać BackHandler do przechwytywania tego zdarzenia:
var backHandlingEnabled by remember { mutableStateOf(true) } BackHandler(backHandlingEnabled) { // Handle back press }
Pierwszy argument określa, czy BackHandler jest obecnie włączony. Możesz go użyć, aby tymczasowo wyłączyć moduł obsługi na podstawie stanu komponentu. Końcowa funkcja lambda zostanie wywołana, jeśli użytkownik aktywuje zdarzenie systemowe cofnięcia, a funkcja BackHandler jest obecnie włączona.
ViewModel
Jeśli używasz biblioteki Architecture Components ViewModel, możesz uzyskać dostęp do ViewModel z dowolnego elementu kompozycyjnego, wywołując funkcję viewModel(). Dodaj do pliku Gradle tę zależność:
Dynamiczny
dependencies { implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.11.0' }
Kotlin
dependencies { implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.11.0") }
Następnie możesz użyć funkcji viewModel() w kodzie.
class MyViewModel : ViewModel() { /*...*/ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { // use viewModel here }
viewModel() zwraca istniejący obiekt ViewModel lub tworzy nowy. Domyślnie zwracany obiekt ViewModel jest ograniczony do aktywności, fragmentu lub miejsca docelowego nawigacji i jest zachowywany tak długo, jak długo zakres jest aktywny.
Jeśli na przykład element kompozycyjny jest używany w aktywności, viewModel() zwraca tę samą instancję, dopóki aktywność nie zostanie zakończona lub proces nie zostanie przerwany.
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
Dostęp do instancji ViewModel uzyskujesz zwykle w funkcjach kompozycyjnych na poziomie ekranu, czyli blisko głównej funkcji kompozycyjnej wywoływanej z aktywności, fragmentu lub miejsca docelowego wykresu nawigacyjnego. Dzieje się tak, ponieważ ViewModel są domyślnie ograniczone do tych obiektów na poziomie ekranu. Więcej informacji o cyklu życia i zakresie ViewModel znajdziesz tutaj.
Staraj się unikać przekazywania instancji ViewModel do innych funkcji kompozycyjnych, ponieważ może to utrudnić testowanie tych funkcji i zakłócić działanie podglądów. Zamiast tego przekazuj tylko dane i funkcje, których potrzebują jako parametrów.
Możesz używać instancji ViewModel do zarządzania stanem funkcji kompozycyjnych na poziomie podekranu, ale pamiętaj o cyklu życia i zakresie ViewModel. Jeśli funkcja kompozycyjna jest samodzielna, możesz rozważyć użycie Hilt do wstrzyknięcia ViewModel, aby uniknąć konieczności przekazywania zależności z funkcji kompozycyjnych nadrzędnych.
Jeśli ViewModel ma zależności, viewModel() przyjmuje opcjonalny parametr ViewModelProvider.Factory.
Więcej informacji o ViewModel w Compose i o tym, jak instancje są używane z biblioteką Navigation Compose, aktywnościami i fragmentami, znajdziesz w dokumentacji dotyczącej interoperacyjności.
strumienie danych,
Compose zawiera rozszerzenia dla najpopularniejszych rozwiązań opartych na strumieniach na 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()zawarte w artefakcieandroidx.compose.runtime:runtime-rxjava2:$composeVersionlubandroidx.compose.runtime:runtime-rxjava3:$composeVersion.
Te artefakty rejestrują się jako detektor i reprezentują wartości jako State. Za każdym razem, gdy emitowana jest nowa wartość, Compose ponownie tworzy te części interfejsu, w których używany jest ten state.value. Na przykład w tym kodzie ShowData jest rekomponowany 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ą współprogramów z poziomu funkcji kompozycyjnych.
Więcej informacji znajdziesz w dokumentacji dotyczącej efektów ubocznych interfejsów API LaunchedEffect, produceState i rememberCoroutineScope.
Nawigacja
Komponent nawigacji obsługuje aplikacje Jetpack Compose. Więcej informacji znajdziesz w artykułach Nawigacja za pomocą Compose i Migracja z Jetpack Navigation do 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 ViewModel z 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() ) { /* ... */ }
Hilt i nawigacja
Hilt integruje się też z biblioteką Navigation Compose. Dodaj do pliku Gradle te dodatkowe zależności:
Dynamiczny
dependencies { implementation 'androidx.hilt:hilt-navigation-compose:1.4.0' }
Kotlin
dependencies { implementation("androidx.hilt:hilt-navigation-compose:1.4.0") }
Podczas korzystania z Navigation Compose zawsze używaj funkcji typu „composable” hiltViewModel, aby uzyskać instancję ViewModel z adnotacją @HiltViewModel.
Działa to z fragmentami lub aktywnościami, które są oznaczone adnotacją @AndroidEntryPoint.
Jeśli na przykład ExampleScreen jest miejscem docelowym na wykresie nawigacyjnym, wywołaj hiltViewModel(), aby uzyskać instancję ExampleViewModel ograniczoną do 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 chcesz pobrać instancję ViewModel ograniczoną do tras nawigacji lub wykresu nawigacji, użyj funkcji typu „composable” hiltViewModel i przekaż odpowiedni parametr 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) } } } }
Paging
Biblioteka Paging ułatwia stopniowe wczytywanie danych i jest obsługiwana w Compose.
Strona wersji Paging zawiera informacje o dodatkowej zależności paging-compose, którą należy dodać do projektu, oraz o 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 korzystaniu ze stronicowania 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 język JavaScript jest wyłączony.
- Efekty uboczne w Compose
- State i Jetpack Compose
- Zapisywanie stanu interfejsu w Compose