Omówienie procesów i wątków

Gdy komponent aplikacji uruchamia się i aplikacja nie ma żadnych innych komponentów Android rozpoczyna nowy proces Linuksa dla aplikacji z pojedynczym wątkiem Domyślnie wszystkie komponenty jednej aplikacji są uruchamiane w ramach tego samego procesu i wątku, tak zwany wątek główny.

Jeśli komponent aplikacji się uruchomi i będzie już mieć proces dla tej aplikacji, ponieważ został już uruchomiony inny komponent z aplikacji, uruchamia się w ramach tego procesu i korzysta z tego samego wątku wykonania. Możesz jednak skonfigurować poszczególne komponenty aplikacji, które będą uruchamiane w oddzielnych procesach. Możesz utworzyć dodatkowe w wątkach dowolnego procesu.

W tym dokumencie opisujemy, jak działają procesy i wątki w aplikacji na Androida.

Procesy

Domyślnie wszystkie komponenty aplikacji działają w ramach tego samego procesu, a większość aplikacji nie zmieniaj tego. Jeśli jednak chcesz kontrolować, który proces dotyczy komponentem, możesz to zrobić w pliku manifestu.

Wpis w pliku manifestu każdego typu elementu komponentu – <activity>, <service>, <receiver> i <provider> – obsługuje atrybut android:process, który może określić w których działa komponent. Możesz ustawić ten atrybut tak, aby każdy komponent działał w ramach własnego procesu. Niektóre komponenty współdzielą proces, a inne nie.

Możesz też określić android:process, aby komponenty różnych aplikacji działały w tym samym czasie o ile aplikacje mają ten sam identyfikator użytkownika systemu Linux i są podpisane same certyfikaty.

<application> obsługuje też atrybut android:process, którego możesz użyć do wartość domyślną, która ma zastosowanie do wszystkich komponentów.

Android może w pewnym momencie wyłączyć proces, gdy zasoby są wymagane przez inne procesy, które są szybciej dostępne dla użytkownika. Aplikacja komponenty uruchomione w trakcie procesu, który został zamknięty, zostaje zniszczony. Rozpoczyna się proces dla tych komponentów, gdy będą gotowe do zrobienia.

Przy podejmowaniu decyzji o tym, które procesy wyłączyć, system Android bierze pod uwagę ich względne znaczenie użytkownika. Na przykład łatwiej zatrzymuje proces hostujący działania, które już nie są widoczne na ekranie w porównaniu z procesem hostującym widoczne działania. Decyzja o tym, zakończenie procesu zależy więc od stanu jego komponentów.

Szczegóły cyklu życia procesu i jego związku ze stanami aplikacji zostały omówione w Procesy i cykl życia aplikacji.

Wątki

Po uruchomieniu aplikacji system tworzy wątek jej wykonania, wątkiem głównym. Ten wątek jest bardzo ważny, ponieważ odpowiada za wysyłanie zdarzeń odpowiednie widżety interfejsu, w tym zdarzenia dotyczące rysowania. Jest także prawie zawsze wątek, w którym aplikacja wchodzi w interakcje z komponentami z narzędzia android.widget i narzędzia interfejsu Androida Liczba pakietów: android.view. Z tego powodu w głównym wątku czasami pojawia się jako wątek interfejsu. Szczególnie jednak w szczególnych okolicznościach główną cechą aplikacji wątek może nie być jego wątkiem UI. Więcej informacji znajdziesz w Thread .

System nie tworzy osobnego wątku dla każdego wystąpienia komponentu. Wszystkie komponenty, które działają w ramach tego samego procesu, są tworzone w wątku interfejsu, a wywołania systemowe a każdy komponent jest wysyłany z tego wątku. Oznacza to, że metody reagujące na system wywołania zwrotne – na przykład onKeyDown() do raportowania działań użytkownika lub metodę wywołania zwrotnego cyklu życia, która jest zawsze uruchamiana w wątku UI danego procesu.

Na przykład: gdy użytkownik dotyka przycisku na ekranie, wątek interfejsu aplikacji wysyła komunikat zdarzenie dotknięcia do widżetu, które z kolei ustawia stan naciśnięcia i przesyła żądanie unieważnienia do kolejki zdarzeń. Wątek interfejsu użytkownika usuwa z kolejki żądanie i powiadamia widżet o ponownym narysowaniu.

Jeśli nie wdrożysz prawidłowo swojej aplikacji, ten model jednowątkowy może generować słabą wydajność, gdy aplikacja wykonuje intensywną pracę w odpowiedzi na interakcje użytkownika. wykonywanie długich operacji w wątku UI, takich jak dostęp do sieci lub zapytań do bazy danych blokuje cały interfejs użytkownika. Gdy wątek jest zablokowany, nie mogą być wysyłane żadne zdarzenia, w tym rysowanie.

Z perspektywy użytkownika aplikacja może się zawieszać. Co gorsza, jeśli wątek UI jest zablokowany na ponad kilka sekund, użytkownik zobaczy „aplikację nie odpowiada (ANR). Użytkownik może zamknąć aplikację lub nawet ją odinstalować. .

Pamiętaj, że zestaw narzędzi interfejsu Androida nie jest przeznaczony do tworzenia wątków. Nie manipuluj więc interfejsu użytkownika z wątku instancji roboczej. Wszystkie czynności związane z interfejsem użytkownika możesz wykonywać z poziomu interfejsu użytkownika. w wątku. W modelu jednowątkowym Androida istnieją 2 reguły:

  1. Nie blokuj wątku UI.
  2. Nie korzystaj z zestawu narzędzi interfejsu Androida spoza wątku UI.

Wątki instancji roboczych

Dzięki temu modelowi jednowątkowemu kluczowe jest reagowanie interfejs aplikacji, aby zapobiec blokowaniu wątku UI. Jeśli masz operacje do wykonania które nie są natychmiastowe, pamiętaj, aby zrobić to w osobnym tle lub worker. Pamiętaj tylko, że nie można zaktualizować interfejsu użytkownika z poziomu wątku innego niż UI, czyli główny wątek.

Aby pomóc Ci w przestrzeganiu tych reguł, Android oferuje kilka sposobów dostępu do wątku UI z poziomu innych aplikacji . Oto lista przydatnych metod:

W tym przykładzie użyto atrybutu View.post(Runnable):

Kotlin

fun onClick(v: View) {
    Thread(Runnable {
        // A potentially time consuming task.
        val bitmap = processBitMap("image.png")
        imageView.post {
            imageView.setImageBitmap(bitmap)
        }
    }).start()
}

Java

public void onClick(View v) {
    new Thread(new Runnable() {
        public void run() {
            // A potentially time consuming task.
            final Bitmap bitmap =
                    processBitMap("image.png");
            imageView.post(new Runnable() {
                public void run() {
                    imageView.setImageBitmap(bitmap);
                }
            });
        }
    }).start();
}

Ta implementacja jest bezpieczna w przypadku wątków, ponieważ operacja w tle jest wykonywana w osobnym wątku gdy obiekt ImageView jest zawsze obsługiwany z poziomu wątku UI.

Jednak wraz ze wzrostem złożoności operacji tego rodzaju kod może być skomplikowany i jest trudny w utrzymaniu. Aby obsługiwać bardziej złożone interakcje z wątkiem instancji roboczej, możesz rozważyć: użycie elementu Handler w wątku instancji roboczej w celu przetwarzania wiadomości dostarczonych z wątku interfejsu użytkownika. Pełne wyjaśnienie, jak zaplanować pracę nad wątkami w tle i komunikować się z wątkiem UI, patrz Omówienie pracy w tle.

Metody bezpieczne dla wątków

W niektórych sytuacjach implementowane przez Ciebie metody są wywoływane z więcej niż 1 wątku, dlatego muszą być napisane w taki sposób, aby nie były wyświetlane w wątkach.

Dotyczy to głównie metod, które mogą być wywoływane zdalnie, takich jak metody w powiązanej usłudze. Przy połączeniu Metoda zastosowana w IBinder pochodzi z tego samego procesu, w którym Metoda IBinder jest uruchomiona, metoda jest wykonywana w wątku wywołującego. Jeśli jednak wywołanie pochodzi z innego procesu, metoda jest wykonywana w wątku wybranym z pula wątków obsługiwanych przez system w ramach tego samego procesu co IBinder. Nie jest wykonywane w wątku interfejsu procesu.

Na przykład, gdy usługa Metoda onBind() jest wywoływana z wątku interfejsu użytkownika proces usługi, metody zaimplementowane w obiekcie zwracanym przez funkcję onBind(), np. podklasa, która implementuje metody zdalnego wywoływania procedur (RPC), jest wywoływana z wątków. w basenie. Usługa może mieć więcej niż jednego klienta, więc może angażować się więcej niż 1 wątek puli tę samą metodę IBinder, więc metody IBinder muszą być są bezpieczne w wątkach.

Podobnie dostawca treści może otrzymywać żądania danych pochodzące z innych procesów. ContentResolver i ContentProvider ukrywają szczegóły dotyczące zarządzania komunikacją międzyprocesową (IPC), ale metody ContentProvider, które odpowiadają na te żądania, czyli metody query(), insert(), delete(), update() i getType() – są jest wywoływane z puli wątków w procesie dostawcy treści, a nie z interfejsu użytkownika. w wątku dotyczącym tego procesu. Ponieważ metody te mogą być wywoływane z dowolnej liczby wątków w jednocześnie, muszą być zaimplementowane, aby były bezpieczne w wątkach.

Komunikacja między procesami

Android oferuje mechanizm IPC wykorzystujący RPC, w którym metoda jest wywoływana przez działanie lub inną aplikację ale został wykonany zdalnie w innym procesie, a wszystkie wyniki są zwracane do . Pociąga to za sobą rozłożenie wywołania metody i jego danych do poziomu dostępnego dla systemu operacyjnego rozumienia i przekazywania jej z procesów lokalnych i przestrzeni adresowej do procesu zdalnego oraz a potem na nowo montować i odtworzyć rozmowę.

Zwracane wartości są następnie w przeciwnym kierunku. Android zapewnia cały kod do wykonywania tych IPC transakcji, możesz więc skupić się na definiowaniu i wdrożeniu interfejsu programowania RPC.

Aby wykonać IPC, aplikacja musi być powiązana z usługą za pomocą bindService(). Więcej informacji znajdziesz w artykule Omówienie usług.