W Compose możesz używać swoich ulubionych bibliotek. W tej sekcji opisujemy, jak włączyć kilka najbardziej przydatnych bibliotek.
Aktywność
Aby używać Compose w aktywności, musisz użyć
ComponentActivity,
czyli podklasy Activity, która udostępnia odpowiedni LifecycleOwner i
komponenty dla Compose. Udostępnia ona też dodatkowe interfejsy API, które oddzielają Twój kod od zastępowania metod w klasie aktywności.
Activity Compose
udostępnia te interfejsy API w elementach kompozycyjnych, 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ą ponowną kompozycję i zostaną prawidłowo wyczyszczone, jeśli element kompozycyjny zostanie usunięty z kompozycji.
Wynik aktywności
Interfejs
rememberLauncherForActivityResult()
API umożliwia
uzyskanie wyniku z aktywności
w elemencie kompozycyjnym:
@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 powoduje wysłanie 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 wczytanie wybranego obrazu za pomocą funkcji rememberImagePainter() biblioteki Coil.
Jako pierwszy argument
rememberLauncherForActivityResult()można użyć dowolnej podklasy
ActivityResultContract.
Oznacza to, że możesz użyć tej metody, aby poprosić o treści z platformy i w innych typowych wzorcach. Możesz też tworzyć własne
kontrakty niestandardowe i używać ich z
tą metodą.
Wysyłanie prośby o uprawnienia czasu działania
Tego samego interfejsu Activity Result API i
rememberLauncherForActivityResult()
opisanych powyżej można używać do
wysyłania prośby o uprawnienia czasu działania
za pomocą kontraktu
RequestPermission
w przypadku pojedynczego uprawnienia lub kontraktu
RequestMultiplePermissions
w przypadku wielu uprawnień.
Biblioteka Accompanist Permissions może też służyć 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ć domyślne działanie systemowego przycisku Wstecz w
elemencie kompozycyjnym, element ten 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 the
BackHandler
jest obecnie włączony. Możesz go użyć, aby tymczasowo wyłączyć obsługę
na podstawie stanu komponentu. Lambda końcowa zostanie wywołana, jeśli użytkownik wywoła zdarzenie systemowe Wstecz, a
BackHandler
jest obecnie włączony.
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.10.0' }
Kotlin
dependencies { implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.10.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 ViewModel lub tworzy nowy. Domyślnie zwrócony ViewModel jest ograniczony do otaczającej aktywności, fragmentu lub miejsca docelowego nawigacji i jest zachowywany tak długo, jak długo istnieje zakres.
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 zakończony.
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 elementach kompozycyjnych na poziomie ekranu, czyli blisko elementu kompozycyjnego głównego wywoływanego z aktywności, fragmentu lub miejsca docelowego wykresu nawigacji. Dzieje się tak, ponieważ ViewModel są domyślnie ograniczone do tych obiektów na poziomie ekranu. Więcej informacji o cyklu życia i zakresie a
ViewModel's
znajdziesz tutaj.
Staraj się nie przekazywać
ViewModel instancji do innych elementów kompozycyjnych, ponieważ może to sprawić, że te elementy kompozycyjne
będą trudniejsze do przetestowania i mogą zepsuć
podglądy. Zamiast tego przekazuj tylko dane i funkcje, których potrzebują, jako parametry.
Możesz używać instancji ViewModel do
zarządzania stanem elementów kompozycyjnych na poziomie podrzędnego ekranu, ale pamiętaj o
ViewModel's
cyklu życia i zakresie. Jeśli element
kompozycyjny jest samodzielny, możesz użyć Hilt do
wstrzyknięcia ViewModel, aby uniknąć przekazywania zależności z nadrzędnych
elementów kompozycyjnych.
Jeśli Twój ViewModel ma zależności, viewModel() przyjmuje opcjonalny
ViewModelProvider.Factory
jako parametr.
Więcej informacji o ViewModel w Compose oraz o tym, jak instancje są używane z biblioteką Navigation Compose, aktywnościami i fragmentami, znajdziesz w dokumentacji dotyczącej współdziałania.
Strumienie danych
Compose zawiera rozszerzenia najpopularniejszych rozwiązań opartych na strumieniach w Androidzie. Każde z tych rozszerzeń jest udostępniane przez inny artefakt:
LiveData.observeAsState()zawarty w artefakcieandroidx.compose.runtime:runtime-livedata:$composeVersion.Flow.collectAsState()nie wymaga dodatkowych zależności.Observable.subscribeAsState()zawarty w artefakcieandroidx.compose.runtime:runtime-rxjava2:$composeVersionlubandroidx.compose.runtime:runtime-rxjava3:$composeVersion.
Te artefakty rejestrują się jako słuchacze i reprezentują wartości jako
State. 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ą współprogramów w elementach kompozycyjnych.
Więcej informacji znajdziesz w dokumentacji dotyczącej efektów ubocznych, w której opisano interfejsy 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 nawigacji Jetpack do nawigacji 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 ViewModel, który Hilt tworzy za pomocą adnotacji @HiltViewModel. Udostepniliś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.3.0' }
Kotlin
dependencies { implementation("androidx.hilt:hilt-navigation-compose:1.3.0") }
Gdy używasz Navigation Compose, zawsze używaj funkcji kompozycyjnej hiltViewModel, aby uzyskać instancję @HiltViewModel z adnotacją ViewModel.
Działa to w przypadku fragmentów lub aktywności z adnotacją @AndroidEntryPoint.
Jeśli na przykład ExampleScreen jest miejscem docelowym na wykresie nawigacji, wywołaj hiltViewModel(), aby uzyskać instancję ExampleViewModel ograniczoną do miejsca docelowego, 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 musisz pobrać instancję ViewModel ograniczoną do
tras nawigacji lub wykresu nawigacji
zamiast tego, użyj funkcji typu „composable” hiltViewModel i przekaż odpowiedni
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 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 używaniu Paging w Compose znajdziesz w dokumentacji dotyczącej list i siatek.
Mapy
Aby udostępnić 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
- Stan i Jetpack Compose
- Zapisywanie stanu interfejsu w Compose