Kompletny przewodnik po zarządzaniu współprogramami w systemie Android: lifecycleScope i viewModelScope

  • Podstawowe różnice pomiędzy zakresem współprogramów powiązanych z ViewModelem i tych powiązanych z cyklem życia interfejsu użytkownika.
  • Wykorzystanie zaawansowanych narzędzi, takich jak repeatOnLifecycle i collectAsStateWithLifecycle, w celu optymalizacji zużycia zasobów.
  • Wdrożenie określonych dyspozytorów w celu oddzielenia logiki biznesowej, odczytu danych i aktualizacji widoków.

Zarządzanie współprogramami w systemie Android: lifecycleScope i viewModelScope

Jeśli zajmujesz się tworzeniem aplikacji na Androida, prawdopodobnie zdajesz sobie sprawę, że zarządzanie zadaniami asynchronicznymi może być prawdziwym problemem, jeśli nie jest prowadzone strategicznie. Z pomocą przychodzą współprogramy Kotlin , pozwalające pisać kod, który wydaje się liniowy, ale działa w tle, zapobiegając zawieszaniu się aplikacji i frustracji użytkownika.

Aby zapobiec katastrofie w postaci wycieków pamięci lub nieoczekiwanych awarii, potrzebujemy tzw. zakresów współprogramów (Coroutine Scopes). Zasadniczo określają one, jak długo powinno trwać zadanie, zanim będzie można je bezpiecznie zakończyć. W tym sensie lifecycleScope i viewModelScope to dwa filary, które każdy programista musi opanować, aby zapewnić płynność i wydajność swojej aplikacji.

ViewModelScope: Strażnik logiki biznesowej

Mówiąc o viewModelScope , mamy na myśli zakres, który jest nierozerwalnie związany z istnieniem ViewModel. Kluczem jest to, że gdy ViewModel zostanie zniszczony (na przykład, gdy użytkownik trwale opuści ekran), każda współprogramowa uruchomiona w tym zakresie zostanie automatycznie anulowana. Jest to niezbędne, aby uniknąć dalszego przetwarzania danych, których nikt nigdy nie zobaczy.

Aby uruchomić program, wystarczy dodać zależność model widoku cyklu życia-ktxW praktyce jest to idealne miejsce do uruchamiania żądań do bazy danych lub wywołań API. Podczas korzystania viewModelScope.launch, zapewniasz, że praca będzie wykonywana wyłącznie w czasie ViewModel jest aktywnyoptymalizując w ten sposób wykorzystanie baterii i pamięci urządzenia.

Dzisiejsze programy telewizyjne Aplikacja na Androida
Powiązany artykuł:
Kotlin: podstawowy język do tworzenia aplikacji na Androida i platform wieloplatformowych

LifecycleScope: pełna kontrola nad interfejsem

W przeciwieństwie do poprzedniej metody, zakres cyklu życia (LifecycleScope) jest bezpośrednio powiązany z obiektem cyklu życia, takim jak aktywność (Activity) lub fragment (Fragment). Oznacza to, że zniszczenie aktywności (Activity) powoduje zniknięcie powiązanych z nią zadań. To idealne narzędzie do operacji bezpośrednio wpływających na warstwę wizualną , takich jak asynchroniczne przygotowywanie złożonego tekstu przed jego wyświetleniem.

Istnieje jednak ważna różnica. Czasami nie chcemy, aby zadanie zostało anulowane przez samo zniszczenie ekranu, ale aby zostało zatrzymane, gdy użytkownik nie będzie go widział. Właśnie tutaj pojawia się funkcja repeatOnLifecycle . Ta funkcja jest nieoceniona, ponieważ umożliwia rozpoczęcie zbierania danych, gdy aplikacja jest w stanie STARTED (uruchomionym ) i automatyczne wstrzymanie po osiągnięciu stanu STOPPED (zatrzymanym) , zapobiegając marnowaniu zasobów przez aplikację w tle.

Zarządzanie przepływami i stanami w Compose

Jeśli już przeszedłeś na Jetpack Compose, zarządzanie przepływem nieco się zmienia. Właśnie tutaj pojawia się `collectAsStateWithLifecycle` . To API to najbezpieczniejszy sposób na konwersję przepływu do stanu zrozumiałego dla Compose, zarządzając subskrypcją zgodnie z cyklem życia komponentu. Jeśli potrzebujesz zebrać wiele przepływów jednocześnie, możesz zadeklarować wiele zmiennych stanu , a Compose obsłuży wszystko płynnie i równolegle.

W przypadkach, gdy konieczne jest asynchroniczne obliczanie wartości, idealnym rozwiązaniem jest użycie StateFlow w połączeniu z stateIn . Pozwala to na przetrwanie danych po zmianach konfiguracji (takich jak obrót ekranu) dzięki parametrowi WhileSubscribed , który utrzymuje połączenie aktywne przez kilka dodatkowych sekund, aby zapobiec niepotrzebnym przeładowaniom.

Dyspozytorzy i sztuka nieblokowania wątku głównego

Niezależnie od używanego zakresu, jeśli uruchomisz zadanie wymagające dużej ilości zasobów w wątku głównym, aplikacja będzie się opóźniać. Właśnie dlatego istnieją zakresy. Dyspozytorzy. Dispatchers.Main Służy wyłącznie do dotykania interfejsu; do wszystkiego innego mamy Dyspozytorzy.IOzoptymalizowany pod kątem odczytu plików i sieci, a także Dispatchers.Default, który jest procesorem zdolnym do wykonywania zadań intensywnie wykorzystujących procesor, takich jak przetwarzanie ogromnego pliku JSON.

Najlepszą praktyką jest uruchomienie współprogramu w wątku głównym, a następnie użycie `withContext` do przełączenia się na wątek roboczy . W ten sposób można wysłać żądanie sieciowe w I/O, a po jego zakończeniu kod wraca do wątku głównego w celu aktualizacji interfejsu użytkownika , nie blokując przy tym środowiska użytkownika.

Dodatkowe narzędzia i kontrola pracy

Za każdym razem, gdy uruchamiamy współprogram z launch o async, otrzymujemy PracaTen obiekt jest jak pilot zdalnego sterowania, który pozwala nam kontrolować zadanie. Możemy go użyć job.join() czekać aż się skończy lub zadanie.anuluj() przerwać operację, jeśli nie jest już konieczna. Należy pamiętać, że async zwraca odroczonyPozwala nam to na równoległe uruchamianie wielu zadań, a następnie zbieranie ich wyników za pomocą funkcji await().

Optymalizacja i kontrola rekompozycji
Powiązany artykuł:
Opanowanie kontroli efektów ubocznych w Jetpack Compose

Jeśli chodzi o konstruktorów, mamy dobrze znany `runBlocking` . Uwaga: blokuje on bieżący wątek i dlatego jest zabroniony w kodzie produkcyjnym aplikacji. Jego prawdziwa użyteczność leży w środowisku testowym , gdzie funkcja zawieszenia musi zakończyć działanie przed sformułowaniem asercji dotyczącej wyniku.

Jasna strategia uruchamiania każdego zadania zapobiega niestabilności aplikacji. Łącząc możliwości viewModelScope dla logiki i lifecycleScope dla widoku, a także inteligentne wykorzystanie dyspozytorów, tworzymy ekosystem, w którym zadania asynchroniczne płynnie przepływają, nie powodując wycieków pamięci ani nie wpływając na wydajność urządzenia. Udostępnij te informacje, aby więcej osób mogło dowiedzieć się więcej na ten temat.


Dodaj jako preferowane źródło w Google