Jaki jest cel Looper i jak go używać?

454

Jestem nowy na Androida. Chcę wiedzieć, co Looperrobi klasa, a także jak z niej korzystać. Przeczytałem dokumentację klasy Android Looper, ale nie jestem w stanie jej w pełni zrozumieć. Widziałem go w wielu miejscach, ale nie mogłem zrozumieć jego celu. Czy ktoś może mi pomóc, określając cel, Loopera także podając prosty przykład, jeśli to możliwe?

Khawar Raza
źródło
7
Właśnie znalazłem wyjątkowo dokładne i jasne wyjaśnienie Looper i jego zastosowania w Safari Books Online. Niestety podejrzewam, że dostęp jest bezpłatny tylko przez ograniczony czas. safaribooksonline.com/library/view/efficient-android-threading/…
Joe Lapp
1
Artykuły i strony referencyjne na Androida wymagają wcześniejszego zapoznania się z poprzednim artykułem. Sugeruję przeczytanie artykułów o aktywności i serwisie w przewodnikach API, a następnie przeczytanie Handler and Looper. Pomaga także, jeśli rozumiesz, czym jest wątek (nie jest to wątek Androida, ale ogólnie wątek ... np. POSIX).
FutureSci
1
Uznałem ten artykuł za przydatny: codetheory.in/…
Herman

Odpowiedzi:

396

Co to jest Looper?

Looper to klasa używana do wykonywania komunikatów (Runnables) w kolejce. Normalne wątki nie mają takiej kolejki, np. Prosty wątek nie ma żadnej kolejki. Wykonuje się raz, a po zakończeniu wykonywania metody wątek nie uruchomi kolejnej wiadomości (Runnable).

Gdzie możemy skorzystać z klasy Looper?

Jeśli ktoś chce wykonać wiele komunikatów (Runnables), powinien użyć klasy Looper, która jest odpowiedzialna za tworzenie kolejki w wątku. Na przykład pisząc aplikację, która pobiera pliki z Internetu, możemy użyć klasy Looper, aby umieścić pliki do pobrania w kolejce.

Jak to działa?

Istnieje prepare()metoda przygotowania Looper. Następnie możesz użyć loop()metody do utworzenia pętli komunikatów w bieżącym wątku, a teraz Twój Looper jest gotowy do wykonania żądań w kolejce, dopóki nie opuścisz pętli.

Oto kod, dzięki któremu możesz przygotować Looper.

class LooperThread extends Thread {
      public Handler mHandler;

      @Override
      public void run() {
          Looper.prepare();

          mHandler = new Handler() {
              @Override
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };

          Looper.loop();
      }
  }
Dharmendra
źródło
17
AsyncTask jest lepszy do tego celu i mniej skomplikowany, ponieważ zawiera wszystkie zarządzanie wątkami.
Fernando Gallego
4
Powinien mieć @Override adnotacje przed biegiem () i handleMessage () metody
Andrew Mackenzie
5
Dokumentacja wskazuje, że musisz wywołać looper.quit. W powyższym kodzie Looper.loop będzie blokował się na czas nieokreślony.
AndroidDev,
2
Jak wyjść z pętli. Mam na myśli gdzie dołączyć Looper.quit () w powyższym przykładzie kodu?
Seenu69,
6
Myślę, że lepiej byłoby użyć HandlerThread, który jest wygodną klasą dla wątku z looper.
Nimrod Dayan
287

Możesz lepiej zrozumieć, czym jest Looper w kontekście GUI. Looper ma zrobić 2 rzeczy.

1) Looper przekształca normalny wątek , który kończy się po powrocie metody run (), w coś działającego nieprzerwanie do momentu uruchomienia aplikacji na Androida , co jest potrzebne w środowisku GUI (technicznie rzecz biorąc, nadal kończy się, gdy metoda run () powróci. Ale pozwól mi wyjaśnij, co mam na myśli poniżej).

2) Looper zapewnia kolejkę, w której zadania do wykonania są kolejkowane, co jest również potrzebne w środowisku GUI.

Jak zapewne wiesz, po uruchomieniu aplikacji system tworzy dla niej wątek wykonawczy, zwany „głównym”, a aplikacje na Androida zwykle domyślnie działają w całości na jednym wątku, domyślnie „głównym wątku”. Ale główny wątek nie jest jakimś tajnym, specjalnym wątkiem . To zwykły wątek podobny do wątków, które tworzysznew Thread() kodu, co oznacza, że ​​kończy się po powrocie metody run ()! Pomyśl o poniższym przykładzie.

public class HelloRunnable implements Runnable {
    public void run() {
        System.out.println("Hello from a thread!");
    }

    public static void main(String args[]) {
        (new Thread(new HelloRunnable())).start();
    }
}

Teraz zastosujmy tę prostą zasadę do aplikacji na Androida. Co by się stało, gdyby aplikacja na Androida działała na normalnym wątku? Wątek o nazwie „main” lub „UI” lub cokolwiek uruchamia twoją aplikację i rysuje cały interfejs użytkownika. Zatem pierwszy ekran jest wyświetlany użytkownikom. Co teraz? Główny wątek kończy się? Nie, nie powinno. Powinien poczekać, aż użytkownicy coś zrobią, prawda? Ale jak możemy osiągnąć takie zachowanie? Cóż, możemy spróbować z Object.wait()lubThread.sleep(). Na przykład główny wątek kończy swoje początkowe zadanie, aby wyświetlić pierwszy ekran i śpi. Budzi się, co oznacza przerwanie, gdy pobierane jest nowe zadanie. Jak dotąd tak dobrze, ale w tej chwili potrzebujemy struktury danych przypominającej kolejkę do obsługi wielu zadań. Pomyśl o przypadku, gdy użytkownik dotknie ekranu szeregowo, a zakończenie zadania zajmuje więcej czasu. Musimy więc mieć strukturę danych, aby przechowywać zadania do wykonania według kolejności zgłoszeń. Można również sobie wyobrazić, że implementacja wątku działającego i przetwarzającego, gdy dotrze do niego przy użyciu przerwania, nie jest łatwa i prowadzi do złożonego i często niemożliwego do utrzymania kodu. W tym celu wolelibyśmy stworzyć nowy mechanizm i na tym właśnie polega Looper . Oficjalny dokument klasy Loopermówi: „Wątki domyślnie nie mają z nimi powiązanej pętli komunikatów”, a Looper jest klasą „używaną do uruchamiania pętli komunikatów dla wątku”. Teraz możesz zrozumieć, co to znaczy.

Aby to wyjaśnić, sprawdźmy kod, w którym główny wątek jest transformowany. Wszystko to dzieje się w klasie ActivityThread . W metodzie main () możesz znaleźć poniższy kod, który zamienia normalny główny wątek w coś, czego potrzebujemy.

public final class ActivityThread {
    ...
    public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();
        Looper.loop();
        ...
    }
}

i Looper.loop()metoda zapętla się w nieskończoność i usuwa z kolejki komunikat i przetwarza pojedynczo:

public static void loop() {
    ...
    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
        ...
        msg.target.dispatchMessage(msg);
        ...
    }
}

Zasadniczo Looper to klasa stworzona w celu rozwiązania problemu występującego w środowisku GUI. Ale tego rodzaju potrzeby mogą się również zdarzyć w innej sytuacji. W rzeczywistości jest to dość znany wzorzec dla aplikacji wielowątkowych i możesz dowiedzieć się więcej na ten temat w „ Concurrent Programming in Java ” Douga Lei (zwłaszcza rozdział 4.1.4 „Wątki robocze” byłby pomocny). Można również sobie wyobrazić, że ten rodzaj mechanizmu nie jest unikalny w systemie Android, ale wszystkie ramy GUI mogą wymagać nieco podobnego do tego. Prawie taki sam mechanizm można znaleźć w frameworku Java Swing.

김준호
źródło
26
To jedyna odpowiedź, która faktycznie tłumaczy, dlaczego klasa Looper byłaby kiedykolwiek używana. Nie jestem pewien, dlaczego nie jest to najlepsza odpowiedź, trzy wyżej ocenione odpowiedzi nic nie wyjaśniają.
Andrew Koster,
4
@AK. Dlatego dodałem tę odpowiedź, nawet gdy wydawało się, że jest za późno. Cieszę się, że moja odpowiedź pomogła ci! :)
김준호
1
@ Hej-men-whatsup Tak
김준호
1
Przed przeczytaniem tego byłem jak „Looper ???” a teraz „O tak, porozmawiajmy o tym”. Dzięki stary, świetna odpowiedź :)
umerk44
Szybkie pytanie. Stwierdziłeś, że w głównym wątku po wyciągnięciu wszystkich elementów interfejsu użytkownika jest uśpiony. Ale powiedzmy, że użytkownik wchodzi w interakcję z przyciskiem na ekranie, czy kliknięcie przycisku nie jest nawet umieszczane w głównej kolejce, to jakiś obiekt wyśle ​​go do prawidłowej aktywności, a następnie główny wątek dla tej aktywności zostanie przebudzony i wykona się kod wywołania zwrotnego dla tego kliknięcia przycisku?
CapturedTree
75

Looper pozwala na wykonywanie zadań sekwencyjnie na jednym wątku. I przewodnik określa te zadania, które musimy wykonać. Jest to typowy scenariusz, który próbuję zilustrować w tym przykładzie:

class SampleLooper extends Thread {
@Override
public void run() {
  try {
    // preparing a looper on current thread     
    // the current thread is being detected implicitly
    Looper.prepare();

    // now, the handler will automatically bind to the
    // Looper that is attached to the current thread
    // You don't need to specify the Looper explicitly
    handler = new Handler();

    // After the following line the thread will start
    // running the message loop and will not normally
    // exit the loop unless a problem happens or you
    // quit() the looper (see below)
    Looper.loop();
  } catch (Throwable t) {
    Log.e(TAG, "halted due to an error", t);
  } 
}
}

Teraz możemy użyć modułu obsługi w innych wątkach (powiedzmy wątek interfejsu użytkownika), aby opublikować zadanie w Looper do wykonania.

handler.post(new Runnable()
{
public void run() {
//This will be executed on thread using Looper.
    }
});

W wątku interfejsu użytkownika mamy domyślny Looper, który pozwala nam obsługiwać wiadomości w wątku interfejsu użytkownika.

użytkownik 2834274
źródło
nie zablokuje żadnego procesu interfejsu użytkownika, czy to prawda?
gumuruh
4
Dziękujemy za
dołączenie
To nie wyjaśnia, dlaczego warto korzystać z tej klasy, tylko jak.
Andrew Koster,
33

Android Looperjest opakowaniem, aby dołączyć MessageQueuedo Threadi zarządza przetwarzania kolejki. Wygląda to bardzo tajemniczo w dokumentacji Androida i wiele razy możemy napotkać Looperpowiązane problemy z dostępem do interfejsu użytkownika. Jeśli nie rozumiemy podstaw, staje się bardzo trudny w obsłudze.

Oto artykuł , który wyjaśnia, Loopercykl życiowy, jak go używać i wykorzystanie LooperwHandler

wprowadź opis zdjęcia tutaj

Looper = Wątek + Komunikat

użytkownik542954
źródło
3
To nie wyjaśnia, dlaczego warto korzystać z tej klasy, tylko jak.
Andrew Koster,
14

Definicja Looper & Handler:

Looper jest klasą, która zamienia wątek w wątek rurociągu, a moduł obsługi udostępnia mechanizm wypychania zadań z dowolnego innego wątku.

Detale:

Tak więc wątek PipeLine jest wątkiem, który może przyjmować więcej zadań z innych wątków za pośrednictwem modułu obsługi.

Looper jest nazwany tak dlatego, że wykonuje pętlę - wykonuje kolejne zadanie, wykonuje go, a następnie wykonuje następny i tak dalej. Moduł obsługi nazywany jest modułem obsługi, ponieważ jest używany do obsługi lub akceptowania następnego zadania za każdym razem z dowolnego innego wątku i przekazywany do Looper (Thread lub PipeLine Thread).

Przykład:

Doskonałym przykładem wątku Looper and Handler lub PipeLine jest pobranie więcej niż jednego obrazu lub przesłanie ich na serwer (HTTP) jeden po drugim w jednym wątku zamiast rozpoczynania nowego wątku dla każdego połączenia sieciowego w tle.

Przeczytaj więcej o Looper i Handler oraz definicji wątku rurociągu:

Android Guts: wprowadzenie do pętli i programów obsługi

ahmadalibaloch
źródło
7

Looper posiada synchronized MessageQueue, który jest używany do przetwarzania wiadomości umieszczonych w kolejce.

Implementuje Threadokreślony wzorzec przechowywania.

Tylko jeden Looperna Thread. Kluczowe metody obejmują prepare(), loop()i quit().

prepare()inicjuje prąd Threadjako Looper. prepare()to staticmetoda wykorzystująca ThreadLocalklasę, jak pokazano poniżej.

   public static void prepare(){
       ...
       sThreadLocal.set
       (new Looper());
   }
  1. prepare() należy wywołać jawnie przed uruchomieniem pętli zdarzeń.
  2. loop()uruchamia pętlę zdarzeń, która czeka, aż Wiadomości dotrą do kolejki komunikatów określonego wątku. Po odebraniu następnego komunikatu loop()metoda wysyła komunikat do docelowego modułu obsługi
  3. quit()zamyka pętlę zdarzeń. Nie kończy pętli, ale zamiast tego wywołuje specjalną wiadomość

Loopermożna zaprogramować w Threadkilku krokach

  1. Poszerzać Thread

  2. Zadzwoń, Looper.prepare()aby zainicjować wątek jakoLooper

  3. Utwórz co najmniej jeden Handler(e), aby przetwarzać przychodzące wiadomości

  4. Wywołaj, Looper.loop()aby przetwarzać wiadomości, dopóki nie pojawi się polecenie zapętlenia quit().
Theo
źródło
5

Żywotność java Wątek dobiegł końca po zakończeniu run()metody. Ten sam wątek nie może zostać ponownie uruchomiony.

Looper przekształca normalną Threadw pętlę komunikatów. Kluczowe metody Looperto:

void prepare ()

Zainicjuj bieżący wątek jako looper. Daje to szansę na utworzenie procedur obsługi, które następnie odwołują się do tego looper'a, zanim faktycznie uruchomi się pętlę. Pamiętaj, aby wywołać pętlę () po wywołaniu tej metody i zakończyć ją wywołaniem quit ().

void loop ()

Uruchom kolejkę komunikatów w tym wątku. Pamiętaj, aby wywołać quit (), aby zakończyć pętlę.

void quit()

Wychodzi z looper'a.

Powoduje zakończenie metody loop () bez przetwarzania kolejnych komunikatów w kolejce komunikatów.

Ten artykuł autorstwa Mindish autorstwa Janishara ładnie wyjaśnia podstawowe pojęcia.

wprowadź opis zdjęcia tutaj

Looperjest powiązany z wątkiem. Jeśli potrzebujesz Looperwątku interfejsu użytkownika, Looper.getMainLooper()zwróci powiązany wątek.

Musisz Looperbyć powiązany z osobą zajmującą się obsługą .

Looper, Handleri HandlerThreadsą sposobem Androida na rozwiązanie problemów programowania asynchronicznego.

Gdy to zrobisz Handler, możesz zadzwonić poniżej API.

post (Runnable r)

Powoduje dodanie Runnable r do kolejki komunikatów. Plik wykonywalny zostanie uruchomiony w wątku, do którego jest dołączony ten moduł obsługi.

boolean sendMessage (Message msg)

Wypycha wiadomość na koniec kolejki wiadomości po wszystkich oczekujących wiadomościach przed bieżącą godziną. Zostanie odebrany w handleMessage (Message), w wątku dołączonym do tego modułu obsługi.

HandlerThread to przydatna klasa do rozpoczynania nowego wątku, który ma pętlę. Looper może być następnie użyty do stworzenia klas procedur obsługi

W niektórych scenariuszach nie można uruchamiać Runnablezadań w wątku interfejsu użytkownika. np. operacje sieciowe: wyślij wiadomość na gniazdo, otwórz adres URL i uzyskaj treść, czytającInputStream

W takich przypadkach HandlerThreadprzydaje się. Można uzyskać Looperobiektu z HandlerThreadi utworzyć Handlerna HandlerThreadzamiast głównego wątku.

HandlerThread kod będzie tak:

@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

Zobacz poniższy kod na przykład kod:

Android: Toast w wątku

Ravindra babu
źródło
5

Zrozumienie wątków Looper

Wątek java Wątek jednostki wykonawczej, która została zaprojektowana do wykonania zadania w metodzie run (), a następnie zakończ: wprowadź opis zdjęcia tutaj

Ale w Androidzie istnieje wiele przypadków użycia, w których musimy utrzymywać wątek przy życiu i czekać na dane wejściowe / zdarzenia użytkownika np. UI wątek aka Main Thread.

Główny wątek w Androidzie to wątek Java, który został po raz pierwszy uruchomiony przez JVM przy uruchomieniu aplikacji i działa dalej, dopóki użytkownik nie zdecyduje się go zamknąć lub napotka nieobsługiwany wyjątek.

Po uruchomieniu aplikacji system tworzy dla niej wątek wykonawczy, nazywany „głównym”. Wątek ten jest bardzo ważny, ponieważ odpowiada za wysyłanie zdarzeń do odpowiednich widżetów interfejsu użytkownika, w tym zdarzeń rysowania.

wprowadź opis zdjęcia tutaj

Teraz należy zauważyć, że chociaż głównym wątkiem jest wątek Java, wciąż słucha on zdarzeń użytkownika i rysuje 60 klatek na sekundę na ekranie, a mimo to nie umrze po każdym cyklu. jak to jest

Odpowiedź brzmi : klasa Looper : Looper to klasa używana do utrzymywania wątku przy życiu i zarządzania kolejką komunikatów w celu wykonywania zadań w tym wątku.

Wątki domyślnie nie mają powiązanej z nimi pętli komunikatów, ale można ją przypisać poprzez wywołanie Looper.prepare () w metodzie run, a następnie wywołanie Looper.loop ().

Celem Looper jest utrzymanie wątku przy życiu i oczekiwanie na następny cykl Messageobiektu wejściowego w celu wykonania obliczeń, które w przeciwnym razie ulegną zniszczeniu po pierwszym cyklu wykonania.

Jeśli chcesz głębiej dowiedzieć się, jak Looper zarządza Messagekolejką obiektów, możesz spojrzeć na kod źródłowy Looperclass:

https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/java/android/os/Looper.java

Poniżej znajduje się przykład, w jaki sposób możesz stworzyć klasę Looper Threadi komunikować się z nią Activityza pomocąLocalBroadcast

class LooperThread : Thread() {

    // sendMessage success result on UI
    private fun sendServerResult(result: String) {
        val resultIntent = Intent(ServerService.ACTION)
        resultIntent.putExtra(ServerService.RESULT_CODE, Activity.RESULT_OK)
        resultIntent.putExtra(ServerService.RESULT_VALUE, result)
        LocalBroadcastManager.getInstance(AppController.getAppController()).sendBroadcast(resultIntent)
    }

    override fun run() {
        val looperIsNotPreparedInCurrentThread = Looper.myLooper() == null

        // Prepare Looper if not already prepared
        if (looperIsNotPreparedInCurrentThread) {
            Looper.prepare()
        }

        // Create a handler to handle messaged from Activity
        handler = Handler(Handler.Callback { message ->
            // Messages sent to Looper thread will be visible here
            Log.e(TAG, "Received Message" + message.data.toString())

            //message from Activity
            val result = message.data.getString(MainActivity.BUNDLE_KEY)

            // Send Result Back to activity
            sendServerResult(result)
            true
        })

        // Keep on looping till new messages arrive
        if (looperIsNotPreparedInCurrentThread) {
            Looper.loop()
        }
    }

    //Create and send a new  message to looper
    fun sendMessage(messageToSend: String) {
        //Create and post a new message to handler
        handler!!.sendMessage(createMessage(messageToSend))
    }


    // Bundle Data in message object
    private fun createMessage(messageToSend: String): Message {
        val message = Message()
        val bundle = Bundle()
        bundle.putString(MainActivity.BUNDLE_KEY, messageToSend)
        message.data = bundle
        return message
    }

    companion object {
        var handler: Handler? = null // in Android Handler should be static or leaks might occur
        private val TAG = javaClass.simpleName

    }
}

Zastosowanie :

 class MainActivity : AppCompatActivity() {

    private var looperThread: LooperThread? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // start looper thread
        startLooperThread()

        // Send messages to Looper Thread
        sendMessage.setOnClickListener {

            // send random messages to looper thread
            val messageToSend = "" + Math.random()

            // post message
            looperThread!!.sendMessage(messageToSend)

        }   
    }

    override fun onResume() {
        super.onResume()

        //Register to Server Service callback
        val filterServer = IntentFilter(ServerService.ACTION)
        LocalBroadcastManager.getInstance(this).registerReceiver(serverReceiver, filterServer)

    }

    override fun onPause() {
        super.onPause()

        //Stop Server service callbacks
     LocalBroadcastManager.getInstance(this).unregisterReceiver(serverReceiver)
    }


    // Define the callback for what to do when data is received
    private val serverReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            val resultCode = intent.getIntExtra(ServerService.RESULT_CODE, Activity.RESULT_CANCELED)
            if (resultCode == Activity.RESULT_OK) {
                val resultValue = intent.getStringExtra(ServerService.RESULT_VALUE)
                Log.e(MainActivity.TAG, "Server result : $resultValue")

                serverOutput.text =
                        (serverOutput.text.toString()
                                + "\n"
                                + "Received : " + resultValue)

                serverScrollView.post( { serverScrollView.fullScroll(View.FOCUS_DOWN) })
            }
        }
    }

    private fun startLooperThread() {

        // create and start a new LooperThread
        looperThread = LooperThread()
        looperThread!!.name = "Main Looper Thread"
        looperThread!!.start()

    }

    companion object {
        val BUNDLE_KEY = "handlerMsgBundle"
        private val TAG = javaClass.simpleName
    }
}

Czy zamiast tego możemy użyć zadania asynchronicznego lub usług intencyjnych?

  • Zadania asynchroniczne są zaprojektowane do wykonywania krótkich operacji w tle i dostarczania postępów i wyników w wątku interfejsu użytkownika. Zadania asynchroniczne mają takie ograniczenia, że ​​nie można utworzyć więcej niż 128 zadań asynchronicznych i ThreadPoolExecutorzezwalają na maksymalnie 5 zadań asynchronicznych .

  • IntentServicessą również zaprojektowane do wykonywania zadań w tle przez nieco dłuższy czas i można LocalBroadcastsię z nimi komunikować Activity. Ale usługi ulegają zniszczeniu po wykonaniu zadania. Jeśli chcesz, aby działał przez dłuższy czas, niż musisz robić, do cholery, jak while(true){...}.

Inne znaczące przypadki użycia Looper Thread:

  • Służy do komunikacji z gniazdem dwukierunkowym, gdy serwer nasłuchuje gniazda klienta i zapisuje potwierdzenie

  • Przetwarzanie bitmapy w tle. Przekaż adres URL obrazu do wątku Looper, a on zastosuje efekty filtrów i zapisze go w lokalizacji tempe rory, a następnie wyemituje tymczasową ścieżkę obrazu.

Hitesh Sahu
źródło
4

Ta odpowiedź nie ma nic wspólnego z pytaniem, ale użycie looper i sposób, w jaki ludzie stworzyli moduł obsługi i looper we WSZYSTKICH tutaj odpowiedziach, są po prostu złą praktyką (choć niektóre wyjaśnienia są poprawne), muszę to opublikować:

HandlerThread thread = new HandlerThread(threadName);
thread.start();
Looper looper = thread.getLooper();
Handler myHandler = new Handler(looper);

i dla pełnego wdrożenia

TacB0sS
źródło
3

Lepszym przykładem jest obsługa wielu elementów w dół lub przesyłanych w usłudze .

Handleri AsnycTasksą często używane do propagowania zdarzeń / komunikatów między interfejsem użytkownika (wątkiem) a wątkiem roboczym lub do opóźniania działań. Są więc bardziej związane z interfejsem użytkownika.

A Looperobsługuje zadania ( Runnables, Futures ) w kolejce powiązanej z wątkami w tle - nawet bez interakcji użytkownika lub wyświetlanego interfejsu użytkownika (aplikacja pobiera plik w tle podczas połączenia).

Thorsten
źródło
1

Co to jest Looper?

Z DOCS

Looper

LooperKlasa używana do uruchomienia pętli komunikatów dla thread. Wątki domyślnie nie są powiązane z pętlą komunikatów; aby go utworzyć, należy wywołać prepare()wątek, który ma uruchomić pętlę, a następnie loop()przetworzyć komunikaty do momentu zatrzymania pętli.

  • A Looperto pętla obsługi komunikatów:
  • Ważną postacią Looper jest to, że jest on powiązany z wątkiem, w którym Looper jest tworzony
  • Klasa Looper utrzymuje a MessageQueue, która zawiera komunikaty listy. Ważną postacią Looper jest to, że jest on powiązany z wątkiem, w którym Looper jest tworzony.
  • LooperNazywa się tak dlatego, że wykonuje pętlę - wykonuje kolejne zadanie, wykonuje go, a następnie wykonuje następny i tak dalej. HandlerNazywamy obsługi dlatego, że ktoś nie mógł wymyślić lepszej nazwy
  • Android Looperto klasa Java w interfejsie użytkownika Androida, która wraz z klasą Handler do przetwarzania zdarzeń interfejsu użytkownika, takich jak kliknięcia przycisków, przerysowywanie ekranu i przełączanie orientacji.

Jak to działa?

wprowadź opis zdjęcia tutaj

Creating Looper

Wątek otrzymuje a Looperi MessageQueuedzwoni Looper.prepare()po jego uruchomieniu. Looper.prepare()identyfikuje wątek wywołujący, tworzy Looper i MessageQueueobiekt oraz kojarzy wątek

PRZYKŁADOWY KOD

class MyLooperThread extends Thread {

      public Handler mHandler; 

      public void run() { 

          // preparing a looper on current thread  
          Looper.prepare();

          mHandler = new Handler() { 
              public void handleMessage(Message msg) { 
                 // process incoming messages here
                 // this will run in non-ui/background thread
              } 
          }; 

          Looper.loop();
      } 
  }

Aby uzyskać więcej informacji, sprawdź poniższy post

Nilesh Rathod
źródło
doskonale, zrozumiałem mechanikę. dzięki
Serg Burlaka