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 uruchamiania współprogramów. Każda operacja asynchroniczna jest wykonywana w określonym zakresie.
Komponenty uwzględniające cykl życia zapewniają najwyższej klasy obsługę współprogramów w zakresach logicznych aplikacji. Z tego dokumentu dowiesz się, jak efektywnie używać współprogramów z komponentami uwzględniającymi cykl życia.
Dodawanie zależności
Wbudowane zakresy współprogramów opisane w tym temacie są zawarte 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 cyklu życia 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 aplikacji.
ViewModelScope
ViewModelScope jest definiowany dla każdego elementu ViewModel w aplikacji. Każda współprogram uruchomiony w tym zakresie jest automatycznie anulowany, jeśli ViewModel zostanie wyczyszczony. Korutyny są przydatne, gdy masz zadanie, które musi zostać wykonane tylko wtedy, gdy ViewModel jest aktywny. Jeśli na przykład obliczasz dane na potrzeby układu, zakres pracy powinien być ograniczony 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 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 obiekt CoroutineScope bezpośrednio do konstruktora ViewModel, aby zastąpić domyślny obiekt viewModelScope. To podejście zapewnia większą kontrolę i elastyczność, zwłaszcza w przypadku:
Testowanie: umożliwia wstrzyknięcie
TestScope, co ułatwia kontrolowanie czasu i weryfikowanie zachowania współprogramu w testach jednostkowych.Konfiguracja niestandardowa: możesz skonfigurować zakres z określonym
CoroutineDispatcher(np.Dispatchers.Defaultw przypadku intensywnych obliczeń) lub niestandardowymCoroutineExceptionHandler, zanim ViewModel w ogóle zacznie działać.
Zakresy powiązane z kompozycją
Efekty uboczne, takie jak animacje, wywołania sieciowe czy liczniki czasu, muszą być ograniczone do cyklu życia funkcji kompozycyjnej. Dzięki temu, gdy funkcja kompozycyjna opuści ekran (wyjdzie z kompozycji), wszystkie działające współprogramy zostaną automatycznie anulowane, aby zapobiec wyciekom pamięci.
Compose udostępnia interfejs API LaunchedEffect do deklaratywnego zarządzania zakresem kompozycji.
LaunchedEffect tworzy CoroutineScope, który umożliwia uruchamianie funkcji zawieszenia. Zakres jest powiązany z cyklem życia kompozycji funkcji kompozycyjnej, a nie z cyklem życia aktywności hosta.
- Wejście: współprogram uruchamia się, gdy funkcja kompozycyjna wchodzi do kompozycji.
- Zakończenie: współprogram jest anulowany, gdy element kompozycyjny opuszcza kompozycję.
- Ponowne uruchomienie: jeśli którykolwiek klucz przekazany do
LaunchedEffectulegnie zmianie, istniejąca współprogram zostanie anulowana i zostanie uruchomiona nowa.
Poniższy przykład pokazuje, jak użyć LaunchedEffect do utworzenia animacji pulsującej. 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 o efektach ubocznych w Compose.
Zbieranie przepływów z uwzględnieniem cyklu życia
Aby bezpiecznie zbierać przepływy w Jetpack Compose, użyj interfejsu API collectAsStateWithLifecycle. Ta pojedyncza funkcja konwertuje obiekt Flow na obiekt Compose State i automatycznie zarządza subskrypcją cyklu życia. Domyślnie zbieranie danych rozpoczyna się, gdy cykl życia ma stan STARTED, a kończy, gdy cykl życia ma stan STOPPED. Aby zastąpić to działanie domyślne, przekaż parametr minActiveState z wybraną metodą cyklu życia, np. Lifecycle.State.RESUMED.
Poniższy przykład pokazuje, jak zebrać StateFlow elementu 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 danych z 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, zbieranie równoległe 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
Jeśli chcesz obliczać wartości asynchronicznie, użyj StateFlow z operatorem stateIn.
Ten fragment kodu używa standardowego elementu Flow przekonwertowanego na StateFlow. Parametr WhileSubscribed(5000) utrzymuje subskrypcję aktywną przez 5 sekund po zniknięciu interfejsu, aby obsłużyć 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 przekonwertować zebrane wartości na Compose State, dzięki czemu interfejs będzie mógł reagować na zmiany danych.
Więcej informacji o stanie znajdziesz w artykule State and Jetpack Compose (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