Współprogramy Kotlin udostępniają interfejs API, który umożliwia pisanie kodu asynchronicznego. Dzięki współprogramom Kotlin możesz zdefiniować CoroutineScope, który
pomaga zarządzać czasem działania współprogramów. Każda operacja asynchroniczna jest wykonywana w określonym zakresie.
Komponenty uwzględniające cykl życia zapewniają najwyższej jakości obsługę współprogramów w zakresach logicznych w aplikacji. Z tego dokumentu dowiesz się, jak efektywnie korzystać ze współprogramów z komponentami uwzględniającymi cykl życia.
Dodawanie zależności
Wbudowane zakresy współprogramów opisane w tym artykule znajdują się w interfejsie Lifecycle API. Pamiętaj, aby podczas korzystania z tych zakresów dodać odpowiednie zależności.
- W przypadku narzędzi ViewModel w Compose użyj
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"). - W przypadku narzędzi Lifecycle w Compose użyj
implementation("androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version").
Zakresy współprogramów uwzględniające cykl życia
Biblioteki Compose i Lifecycle udostępniają te wbudowane zakresy, których możesz używać w swojej aplikacji.
ViewModelScope
Dla każdego ViewModel w aplikacji jest zdefiniowany ViewModelScope. Każdy
współprogram uruchomiony w tym zakresie jest automatycznie anulowany, jeśli ViewModel zostanie
wyczyszczony. Współprogramy są przydatne, gdy masz do wykonania zadanie, które musi zostać wykonane tylko wtedy, gdy ViewModel jest aktywny. Jeśli na przykład obliczasz dane dla układu, powinieneś ograniczyć zakres pracy do ViewModel, aby w przypadku wyczyszczenia ViewModel praca została automatycznie anulowana, co pozwoli uniknąć zużywania zasobów.
Dostęp do CoroutineScope elementu ViewModel możesz uzyskać za pomocą właściwości viewModelScope elementu ViewModel, jak pokazano w tym przykładzie:
class MyViewModel: ViewModel() {
init {
viewModelScope.launch {
// Coroutine that will be canceled when the ViewModel is cleared.
}
}
}
W bardziej zaawansowanych przypadkach użycia możesz przekazać niestandardowy CoroutineScope bezpośrednio do konstruktora ViewModel, aby zastąpić domyślny viewModelScope. To podejście zapewnia większą kontrolę i elastyczność, szczególnie w przypadku:
Testowania: umożliwia wstrzyknięcie
TestScope, co ułatwia kontrolowanie czasu i weryfikowanie zachowania współprogramu w testach jednostkowych.Konfiguracji niestandardowej: możesz skonfigurować zakres za pomocą konkretnego
CoroutineDispatcher(np.Dispatchers.Defaultw przypadku złożonych obliczeń) lub niestandardowegoCoroutineExceptionHandler, zanim ViewModel rozpocznie pracę.
Zakresy powiązane z kompozycją
Efekty uboczne, takie jak animacje, wywołania sieciowe czy timery, muszą być ograniczone do cyklu życia funkcji kompozycyjnej. Dzięki temu, gdy funkcja kompozycyjna opuści ekran (zakończy kompozycję), wszystkie uruchomione współprogramy zostaną automatycznie anulowane, aby zapobiec wyciekom pamięci.
Compose udostępnia interfejs API LaunchedEffect, który umożliwia deklaratywne obsługiwanie zakresu kompozycji.
LaunchedEffect tworzy CoroutineScope, który umożliwia uruchamianie funkcji zawieszających. Zakres jest powiązany z cyklem życia kompozycji funkcji kompozycyjnej, a nie z cyklem życia aktywności hosta.
- Wejście: współprogram rozpoczyna się, gdy funkcja kompozycyjna wchodzi w skład kompozycji.
- Wyjście: współprogram jest anulowany, gdy funkcja kompozycyjna opuszcza kompozycję.
- Ponowne uruchomienie: jeśli zmieni się dowolny klucz przekazany do
LaunchedEffect, dotychczasowy współprogram zostanie anulowany i uruchomiony zostanie nowy.
Ten przykład pokazuje, jak używać LaunchedEffect do tworzenia animacji pulsowania. Współprogram jest powiązany z obecnością funkcji kompozycyjnej w kompozycji i reaguje na zmiany konfiguracji:
// Allow the pulse rate to be configured, so it can be sped up if the user is running // out of time var pulseRateMs by remember { mutableLongStateOf(3000L) } val alpha = remember { Animatable(1f) } LaunchedEffect(pulseRateMs) { // Restart the effect when the pulse rate changes while (isActive) { delay(pulseRateMs) // Pulse the alpha every pulseRateMs to alert the user alpha.animateTo(0f) alpha.animateTo(1f) } }
Więcej informacji o LaunchedEffect znajdziesz w artykule Efekty uboczne w Compose.
Kolekcja przepływów uwzględniająca cykl życia
Aby bezpiecznie zbierać przepływy w Jetpack Compose, użyj interfejsu API
collectAsStateWithLifecycle. Ta pojedyncza funkcja przekształca Flow w obiekt State Compose i automatycznie zarządza subskrypcją cyklu życia. Domyślnie zbieranie rozpoczyna się, gdy cykl życia jest STARTED, a kończy się, gdy cykl życia jest STOPPED. Aby zastąpić to domyślne zachowanie, przekaż parametr minActiveState z wybraną metodą cyklu życia, np. Lifecycle.State.RESUMED.
Ten przykład pokazuje, jak zbierać StateFlow ViewModel w funkcji kompozycyjnej:
@Composable private fun ConversationScreen( conversationViewModel: ConversationViewModel = viewModel() ) { val messages by conversationViewModel.messages.collectAsStateWithLifecycle() ConversationScreen( messages = messages, onSendMessage = { message: Message -> conversationViewModel.sendMessage(message) } ) } @Composable private fun ConversationScreen( messages: List<Message>, onSendMessage: (Message) -> Unit ) { MessagesList(messages, onSendMessage) /* ... */ }
Równoległe zbieranie wielu przepływów
W Compose możesz zbierać wiele przepływów równolegle, deklarując wiele zmiennych stanu. Ponieważ collectAsStateWithLifecycle zarządza własnym zakresem bazowym, równoległe zbieranie jest obsługiwane automatycznie:
@Composable
fun DashboardScreen(viewModel: DashboardViewModel = viewModel()) {
// Both flows are collected safely in parallel and will emit updates when either changes, the composables will recompose
val userData by viewModel.userFlow.collectAsStateWithLifecycle()
val feedData by viewModel.feedFlow.collectAsStateWithLifecycle()
// ...
}
Asynchroniczne obliczanie wartości za pomocą przepływów
Gdy musisz obliczyć wartości asynchronicznie, użyj StateFlow z operatorem stateIn.
Ten fragment kodu używa standardowego Flow przekształconego w StateFlow. Parametr
WhileSubscribed(5000) utrzymuje subskrypcję aktywną przez pięć
sekund po zniknięciu interfejsu, aby obsługiwać zmiany konfiguracji.
val uiState: StateFlow<Result> = flow {
emit(repository.fetchData())
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = Result.Loading
)
Użyj collectAsStateWithLifecycle, aby przekształcić zebrane wartości w Compose
State, dzięki czemu interfejs będzie mógł reagować na zmiany danych.
Więcej informacji o stanie znajdziesz w artykule Stan i Jetpack Compose.
Dodatkowe materiały
Wyświetlanie treści
Przykłady
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy język JavaScript jest wyłączony.
- Obsługa cykli życia za pomocą komponentów uwzględniających cykl życia
- Wczytywanie i wyświetlanie danych podzielonych na strony