Android: Kiedy należy używać Handler (), a kiedy wątku?


129

Kiedy potrzebuję czegoś do asynchronicznego działania , na przykład długotrwałego zadania lub logiki korzystającej z sieci, lub z jakiegokolwiek powodu, uruchomienie nowego wątku i uruchomienie działa dobrze. Utworzenie Handlera i uruchomienie go również działa. Co za różnica? Kiedy powinienem używać każdego z nich? Jakie są zalety / powody używania a, Handlera nie a Thread?

PS. - Ze względu na to pytanie zignorujmy AsyncTask. - Handler().postDelayedprzypadek użycia jest dla mnie jasny, ze względu na to pytanie załóżmy, że potrzebuję natychmiastowego uruchomienia zadania.


W twojej sytuacji po prostu idź prosto i użyj nowego wątku, moja następna sugestia to AsyncTask, ale nie tego chcesz. Programy obsługi są najczęściej używane, jeśli chcesz dodać opóźnienie lub inny rodzaj dostosowania do pliku wykonywalnego.
kabuto178,

1
@ kabuto178 Cóż, istnieją inne zalety programów obsługi, o których warto wspomnieć, że je pominąłeś. Na przykład możliwość interakcji z wątkiem interfejsu użytkownika z osobnego wątku ..
tony9099

Odpowiedzi:


169

Jeśli cokolwiek robisz, jest „ciężkie”, powinieneś to robić w wątku. Jeśli nie uruchomisz go jawnie we własnym wątku, będzie on działał w wątku głównym (UI), który może być zauważalny jako roztrzęsiony lub wolno reagujący interfejs użytkowników.

Co ciekawe, gdy używasz wątku, często przydatne jest również użycie Handlera jako środka komunikacji między wątkiem roboczym, który rozpoczynasz, a wątkiem głównym.

Typowa interakcja wątek / obsługa może wyglądać mniej więcej tak:

Handler h = new Handler(){
    @Override
    public void handleMessage(Message msg){
        if(msg.what == 0){
            updateUI();
        }else{
            showErrorDialog();
        }
    }
};

Thread t = new Thread() {
    @Override
    public void run(){
        doSomeWork();
        if(succeed){
            //we can't update the UI from here so we'll signal our handler and it will do it for us.
            h.sendEmptyMessage(0);
        }else{
            h.sendEmptyMessage(1);
        }
    }   
};

Ogólnie rzecz biorąc, najważniejsze jest to, że powinieneś używać wątku za każdym razem, gdy wykonujesz jakąś pracę, która może być długotrwała lub bardzo intensywna (np. Wszystko w sieci, we / wy pliku, ciężka arytmetyka itp.)


Dzięki za szybką odpowiedź i zainwestowany czas (i szybkość Twojej odpowiedzi !!)! Zobaczmy więc, czy mam to: program obsługi został zaprojektowany w celu ułatwienia komunikacji nieblokującej między wątkami roboczymi a wątkiem interfejsu użytkownika?
JRun

3
@JRun To jedno z zastosowań tak. Zapoznaj się z opisem programu obsługi w dokumentacji java, aby uzyskać świetne informacje na ten temat. W tym inne z jego zastosowań (do planowania komunikatów i elementów wykonawczych do wykonania w pewnym momencie w przyszłości).
FoamyGuy

ładnie wyjaśnione @FoamyGuy!
tony9099

Cześć, czy jest gwarantowane, że updateUI()będzie działać po onCreateView(po załadowaniu nowych widoków)?
Zyoo,

1
Dlaczego tak jest message.what()? Czy nie byłoby po prostu if(msg == 0){? Dzięki wielkie! :)
Ruchir Baronia

65

Handler i Thread to tak naprawdę dwie różne rzeczy.

Aby wykonywać długotrwałe zadania, należy utworzyć wątek.

Handler jest bardzo wygodnym obiektem do komunikacji między 2 wątkami (na przykład: wątek działający w tle wymaga aktualizacji interfejsu użytkownika. Możesz użyć Handlera, aby opublikować część Runnable z wątku w tle do wątku interfejsu użytkownika).

Więc nie masz wyboru między obsługą a wątkiem. Użyj nici do ciężkich prac! (możesz użyć Handlera, jeśli twój wątek w tle wyzwoli pewne zadanie do wykonania w innym wątku - w większości przypadków wątek interfejsu użytkownika)


Dzięki za szybką odpowiedź i zainwestowany czas (i szybkość Twojej odpowiedzi !!)!
JRun

28

Handleri Threadto dwie różne rzeczy, ale nie są one sprzeczne. Możesz mieć a Handleri Threadw tym samym czasie i właściwie każdy z nich Handlermusi być uruchomiony w Thread.

Aby uzyskać więcej informacji, zapoznaj się z tym artykułem .

wprowadź opis obrazu tutaj


19

A Handlerdziała na tym samym Thread, a Threaddziała na innym wątku.

Użyj Handlera, jeśli chcesz uruchomić coś w tym samym wątku , zwykle element GUI lub coś podobnego.

Użyj wątku, jeśli chcesz, aby główny wątek mógł robić inne rzeczy . Użyj tego do wszystkiego, co zajmuje dużo czasu.


6
dlaczego powinienem używać programu obsługi, jeśli chcę uruchomić coś w tym samym wątku? jaki jest cel metody mHandler.post (...)?
Elias,

1
Elias, w takim przypadku możesz użyć programu obsługi, jeśli chcesz, aby określone zadanie było uruchamiane po określonym czasie lub aby powtarzać zadanie co X razy. Jeśli nie chcesz używać tych rzeczy, masz rację. używanie obsługi jest niegodne. możesz po prostu robić rzeczy z GUI właśnie tam, a potem bcoz jesteś w wątku UI, ponieważ program obsługi działa w wątku, w którym został utworzony.
tony9099

14

Programy obsługi to najlepszy sposób komunikacji między tłem a wątkiem interfejsu użytkownika. Zwykle programy obsługi są powiązane z kolejką wiadomości wątku i służą do wysyłania wiadomości i mogą być uruchamiane w wiadomości.

POSŁUGIWAĆ SIĘ:

Wątek: Aby wykonać zadania w wątku saperate (w tle) niż wątek interfejsu użytkownika. (pomaga odblokować wątek UI)

Handler Służy do komunikacji między interfejsem użytkownika a wątkiem w tle.

Spójrz na ten artykuł


4

Jeśli chcesz zaktualizować interfejs użytkownika z nowego wątku, musisz zsynchronizować się z wątkiem interfejsu użytkownika.

W tym celu można użyć klasy android.os.Handler lub klasy AsyncTasks.

Klasa Handler może aktualizować interfejs użytkownika. Handler udostępnia metody do odbierania wystąpień klasy Message lub Runnable.

W wątku można publikować wiadomości za pomocą metody sendMessage (Message msg) lub metody sendEmptyMessage ().

... więcej szczegółów tutaj o nici itp (zawiera turorials dla różnych mechanizmów gwintowania i synchronizację i kiedy używać co)


Dziękuję za poświęcenie czasu na odpowiedź na moje pytanie. Uwielbiam blog Larsa Vogela, jest bardzo wnikliwy i łatwy do naśladowania. Dzięki!
JRun

2

Jakie są zalety / powody korzystania z programu obsługi, a nie wątku?

Handler pozwala na wysyłanie i przetwarzania wiadomości i Runnableprzedmioty związane z wątku MessageQueue. Każda Handlerinstancja jest powiązana z pojedynczym wątkiem i kolejką komunikatów tego wątku.

Kiedy tworzysz nowy Handler, jest on powiązany z wątkiem / kolejką komunikatów wątku, który go tworzy - od tego momentu będzie dostarczał komunikaty i pliki do uruchomienia do tej kolejki komunikatów i wykonywał je, gdy wychodzą z kolejki komunikatów .

Procedura obsługi ma dwa główne zastosowania:

  1. Aby zaplanować wykonanie komunikatów i elementów Runnables w przyszłości
  2. Aby umieścić w kolejce akcję, która ma być wykonana w innym wątku niż Twój własny.

Jeśli używasz wątków Java, musisz sobie z czymś poradzić samodzielnie - synchronizacją z wątkiem głównym, anulowaniem wątku itp.

Ten pojedynczy wątek nie tworzy puli wątków, chyba że używasz interfejsu API ThreadPoolExecutorlub ExecutorService.

(Zaczerpnięto to zapytanie z twoich komentarzy do odpowiedzi Blackbelt)

Dlaczego nie skorzystać z Executora? a nawet jeśli chciałbym do tego użyć Handlera, w jaki sposób?

Źródła: artykuł dotyczący wydajności wątków

Istnieją pewne rodzaje pracy, które można zredukować do wysoce równoległych, rozproszonych zadań. Przy ogromnej ilości pakietów roboczych tworzy to AsyncTaski HandlerThreadnie jest to odpowiednie klasy. AsyncTaskJednowątkowy charakter zmieniłby całą pracę w puli wątków w system liniowy. HandlerThreadZ drugiej strony korzystanie z klasy wymagałoby od programisty ręcznego zarządzania równoważeniem obciążenia między grupą wątków.

ThreadPoolExecutor to klasa pomocnicza ułatwiająca ten proces. Ta klasa zarządza tworzeniem grupy wątków, ustala ich priorytety i zarządza sposobem podziału pracy między te wątki. Wraz ze wzrostem lub spadkiem obciążenia klasa obraca się lub niszczy więcej wątków, aby dostosować się do obciążenia.

 BlockingQueue workQueue= new LinkedBlockingQueue<Runnable>(100); // Work pool size
 ThreadPoolExecutor executor = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),       // Initial pool size
            Runtime.getRuntime().availableProcessors(),       // Max pool size
            1, // KEEP_ALIVE_TIME
            TimeUnit.SECONDS, //  KEEP_ALIVE_TIME_UNIT
            workQueue);

Więcej informacji można znaleźć w tym artykule przewodnika dla programistów na temat tworzenia puli wątków .

Spójrz na ten post, aby zapoznać się z używaniem programu Handlerdo uruchamiania wielu instancji Runnable. W takim przypadku wszystkie Runnablezadania będą uruchamiane w jednym wątku.

Android: Toast w wątku


1

Handlermoże być używany w połączeniu z Threadw celu utworzenia mechanizmu kolejkowania. Możesz użyć, handleraby opublikować coś naThread Looper


Dziękuję za poświęcenie czasu na odpowiedź na moje pytanie. Dlaczego nie skorzystać z Executora? a nawet jeśli chciałbym do tego użyć Handlera, w jaki sposób?
JRun

executor jest nieco inny. Aby z niego skorzystać, należy rozszerzyć wątek iw trakcie uruchomienia wywołać static.metohd Prepar.z klasy Looper. po wywołaniu pętli metod statycznych tworzona jest kolejka i możesz użyć kolejności handlerbin do przekazywania żądań i zwracania wyników
Blackbelt

0

Jeśli musisz wykonać zadanie tylko raz oddzielnie poza głównym wątkiem, użyj Thread. Jeśli chcesz wielokrotnie wykonywać zadania, system Android zapewnia sposób na utrzymanie wątków przy życiu i odbieranie wiadomości lub obiektów Runnable do przetwarzania ich za pomocą Looper w MessageQueue.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.