Tworzenie i inne biblioteki

W funkcji Utwórz możesz używać swoich ulubionych bibliotek. W tej sekcji opisujemy, jak wdrożyć kilka najprzydatniejszych bibliotek.

Aktywność

Aby użyć funkcji Utwórz w aktywności, musisz użyć ComponentActivity – podklasy Activity, która dostarcza odpowiednich elementów LifecycleOwner i komponentów do tworzenia. Zapewnia też dodatkowe interfejsy API, które odłączają Twój kod od metod zastępowania w klasie aktywności. Funkcja Activity Compose udostępnia te interfejsy API w funkcjach kompozycyjnych, dzięki czemu zastępowanie metod spoza funkcji kompozycyjnych lub pobieranie jawnej instancji Activity nie jest już wymagane. Co więcej, te interfejsy API zapewniają, że są one inicjowane tylko raz, mogą przetrwać zmianę kompozycji i czyścić poprawnie po usunięciu z kompozycji elementu kompozycyjnego.

Wynik aktywności

Interfejs API rememberLauncherForActivityResult() umożliwia uzyskanie wyniku na podstawie działania w komponencie:

@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 spowoduje wysłanie prośby. Końcowa funkcja lambda dla funkcji rememberLauncherForActivityResult() jest wywoływana, gdy użytkownik wybierze obraz i powróci do uruchamiania działania. Spowoduje to wczytanie wybranego obrazu za pomocą funkcji rememberImagePainter() cewki.

Jako pierwszego argumentu rememberLauncherForActivityResult() można użyć dowolnej podklasy ActivityResultContract. Oznacza to, że możesz używać tej metody do wysyłania żądań treści z platformy oraz innych typowych wzorców. Możesz też tworzyć własne umowy i używać ich w tej metodzie.

Prośba o uprawnienia w czasie działania

Ten sam interfejs Activity Result API i interfejs rememberLauncherForActivityResult(), jak opisano powyżej, mogą być używane do prośby o uprawnienia w czasie działania za pomocą umowy RequestPermission na jedno uprawnienie lub RequestMultiplePermissions udzielania kilku uprawnień.

Z biblioteki uprawnień dotyczących aplikacji Accompanist można również korzystać w warstwie nad tymi interfejsami API do mapowania bieżącego stanu przyznanych uprawnień na stan, z którego może korzystać interfejs użytkownika tworzenia wiadomości.

Obsługa systemowego przycisku Wstecz

Aby udostępnić niestandardową nawigację wsteczną i zastąpić domyślne działanie systemowego przycisku Wstecz z poziomu funkcji kompozycyjnej, funkcja kompozycyjna może przechwycić to zdarzenie za pomocą elementu BackHandler:

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

Pierwszy argument określa, czy funkcja BackHandler jest obecnie włączona. Za pomocą tego argumentu możesz tymczasowo wyłączyć moduł obsługi na podstawie stanu komponentu. Końcowa funkcja lambda jest wywoływana, jeśli użytkownik wywoła systemowe zdarzenie wsteczne, a zdarzenie BackHandler jest obecnie włączone.

ViewModel

Jeśli używasz biblioteki ViewModel komponentów architektury, możesz uzyskać dostęp do ViewModel z dowolnego elementu kompozycyjnego, wywołując funkcję viewModel().

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

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

Funkcja viewModel() zwraca istniejący obiekt ViewModel lub tworzy nową w podanym zakresie. ViewModel jest zachowywany, dopóki zakres jest aktywny. Jeśli na przykład w działaniu jest używany element kompozycyjny, viewModel() zwraca tę samą instancję do czasu zakończenia działania lub jego zakończenia.

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

Jeśli model ViewModel zawiera zależności, viewModel() przyjmuje jako parametr opcjonalny ViewModelProvider.Factory.

Więcej informacji o funkcjach ViewModel w funkcji tworzenia wiadomości oraz sposobach ich wykorzystywania z biblioteką funkcji nawigacji nawigacji, a także o działaniach i fragmentach znajdziesz w dokumentacji dotyczącej współdziałania.

Strumienie danych

Funkcja tworzenia wiadomości ma rozszerzenia do najpopularniejszych rozwiązań opartych na strumieniach na Androidzie. Każde z tych rozszerzeń jest dostarczane przez inny artefakt:

Te artefakty są rejestrowane jako detektor i reprezentują wartości jako State. Po pojawieniu się nowej wartości funkcja Utwórz ponownie składa te części interfejsu, w których jest używany state.value. Na przykład w tym kodzie ShowData tworzy nową kompozycję za każdym razem, gdy exampleLiveData wyemituje 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 oknie tworzenia

Jetpack Compose umożliwia wykonywanie operacji asynchronicznych za pomocą współprogramów z funkcji kompozycyjnych.

Więcej informacji znajdziesz w sekcji dotyczącej interfejsów API LaunchedEffect, produceState i rememberCoroutineScope w dokumentacji efektów ubocznych.

Komponent Nawigacja zapewnia obsługę aplikacji Jetpack Compose. Więcej informacji znajdziesz w artykułach Nawigacja przy użyciu tworzenia wiadomości i Migracja nawigacji Jetpack do funkcji Navigation Compose.

Ręka

Hilt to zalecane rozwiązanie do wstrzykiwania zależności w aplikacjach na Androida, które bezproblemowo współpracuje z funkcją Compose.

Funkcja viewModel() wymieniona w sekcji ViewModel automatycznie używa modelu ViewModel utworzonego przez Hilt z adnotacją @HiltViewModel. Udostępniliśmy dokumentację z informacjami o integracji ViewModel firmy 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()
) { /* ... */ }

Wskazówki i nawigacja

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

Odlotowy

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

Kotlin

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

Jeśli korzystasz z nawigacji tworzenia wiadomości, zawsze używaj funkcji kompozycyjnej hiltViewModel, aby uzyskać wystąpienie elementu @HiltViewModel z adnotacjami ViewModel. Dotyczy to fragmentów lub działań z adnotacjami @AndroidEntryPoint.

Jeśli np. miejsce docelowe ExampleScreen na wykresie nawigacyjnym, wywołaj hiltViewModel(), aby uzyskać wystąpienie ExampleViewModel o zakresie ograniczonym 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 zamiast tego chcesz pobrać instancję obiektu ViewModel o zakresie do tras nawigacyjnych lub wykresu nawigacyjnego, użyj funkcji kompozycyjnej hiltViewModel i prześlij odpowiedni parametr 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)
            }
        }
    }
}

Podział

Biblioteka stron docelowych ułatwia stopniowe ładowanie danych. Jest obsługiwana w narzędziu do tworzenia wiadomości. Strona wersji strony 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 API biblioteki stronicowania:

@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 z funkcji Stron w komponencie znajdziesz w dokumentacji list i siatek.

Mapy firmy Apple

Aby udostępnić Mapy Google w swojej aplikacji, możesz użyć biblioteki Map 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 = MarkerState(position = singapore),
            title = "Singapore",
            snippet = "Marker in Singapore"
        )
    }
}