534 Stimmen

Was ist der Zweck von Looper und wie wird er verwendet?

Ich bin neu bei Android. Ich möchte wissen, was die Looper Klasse und wie man sie benutzt. Ich habe die Android Dokumentation der Looper-Klasse aber ich bin nicht in der Lage, sie vollständig zu verstehen. Ich habe es an vielen Stellen gesehen, aber ich kann seinen Zweck nicht verstehen. Kann mir jemand helfen, indem er den Zweck von Looper und wenn möglich auch mit einem einfachen Beispiel?

15voto

Hitesh Sahu Punkte 37527

Verstehen von Looper Threads

Ein Java-Thread ist eine Ausführungseinheit, die für die Ausführung einer Aufgabe in ihrer run()-Methode konzipiert wurde und danach beendet wird: enter image description here

Aber in Android gibt es viele Anwendungsfälle, in denen wir einen Thread am Leben halten und auf Benutzereingaben/Ereignisse warten müssen, z. B. UI-Thread aka Main Thread .

Der Hauptthread in Android ist ein Java-Thread, der von der JVM beim Start einer Anwendung gestartet wird und so lange läuft, bis der Benutzer ihn schließt oder eine unbehandelte Ausnahme auftritt.

Wenn eine Anwendung gestartet wird, erstellt das System einen Thread von Ausführungsstrang für die Anwendung, genannt "main". Dieser Thread ist sehr wichtig, weil er für die Weiterleitung von Ereignissen an die Ereignisse an die entsprechenden Widgets der Benutzeroberfläche, einschließlich der Zeichenereignisse.

enter image description here

Jetzt Punkt hier zu beachten ist, obwohl Haupt-Thread ist Java-Thread noch es hält auf Benutzer-Ereignisse zu hören und zeichnen 60 fps Frames auf dem Bildschirm und noch es nicht nach jedem Zyklus sterben. wie ist es so?

Die Antwort lautet: Looper Class : Looper ist eine Klasse, die dazu dient, einen Thread am Leben zu erhalten und eine Nachrichtenwarteschlange zu verwalten, um Aufgaben auf diesem Thread auszuführen. diesem Thread auszuführen.

Threads sind standardmäßig nicht mit einer Nachrichtenschleife verknüpft, aber Sie können eine zuweisen, indem Sie Looper.prepare() in der Run-Methode aufrufen und dann Looper.loop() aufrufen.

Der Zweck von Looper ist es, einen Thread am Leben zu erhalten und auf den nächsten Zyklus von Eingabe Message Objekt, um Berechnungen durchzuführen, die sonst nach dem ersten Zyklus der Ausführung zerstört wird.

Wenn Sie mehr darüber erfahren möchten, wie Looper die Message Objektwarteschlange, dann können Sie sich den Quellcode von Looperclass :

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

Im Folgenden finden Sie ein Beispiel dafür, wie Sie eine Looper Thread und kommunizieren mit Activity Klasse mit 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

    }
}

使用方法 :

 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
    }
}

Können wir stattdessen Async-Aufgaben oder Intent Services verwenden?

  • Async-Tasks sind dazu gedacht, kurze Operationen im Hintergrund auszuführen und Fortschritte und Ergebnisse auf dem UI-Thread anzuzeigen. Async-Aufgaben haben Grenzen, z. B. können Sie nicht mehr erstellen als 128 Asynchrone Aufgaben y ThreadPoolExecutor wird nur erlauben bis zu 5 asynchrone Aufgaben .

  • IntentServices sind auch dafür ausgelegt, Hintergrundaufgaben für eine etwas längere Dauer zu erledigen, und Sie können LocalBroadcast zu kommunizieren mit Activity . Aber die Dienste werden nach der Ausführung der Aufgabe zerstört. Wenn Sie sie für eine lange Zeit laufen lassen wollen, müssen Sie Prüfungen durchführen wie while(true){...} .

Andere sinnvolle Anwendungsfälle für Looper Thread:

  • Wird für die 2-Wege-Socket-Kommunikation verwendet, bei der der Server weiterhin auf den Client-Socket hört und eine Bestätigung zurückschreibt.

  • Bitmap-Verarbeitung im Hintergrund. Übergeben Sie das Bild url zu Looper Thread und es wird Filter-Effekte anwenden und speichern Sie es in tempe rory Speicherort und dann Broadcast temp Pfad des Bildes.

7voto

Theo Punkte 2989

A Looper hat eine synchronized MessageQueue die für die Verarbeitung der Nachrichten in der Warteschlange verwendet wird.

Sie implementiert eine Thread Spezifisches Speichermuster.

Nur eine Looper per Thread . Zu den wichtigsten Methoden gehören prepare() , loop() y quit() .

prepare() initialisiert die aktuelle Thread als Looper . prepare() es static Methode, die die ThreadLocal Klasse wie unten gezeigt.

   public static void prepare(){
       ...
       sThreadLocal.set
       (new Looper());
   }
  1. prepare() muss vor der Ausführung der Ereignisschleife explizit aufgerufen werden.
  2. loop() führt die Ereignisschleife aus, die auf den Eingang von Nachrichten in der Nachrichtenwarteschlange eines bestimmten Threads wartet. Sobald die nächste Nachricht eingetroffen ist, wird die loop() Methode sendet die Nachricht an ihren Ziel-Handler
  3. quit() schließt die Ereignisschleife ab. Die Schleife wird nicht beendet, sondern es wird eine spezielle Nachricht in die Warteschlange gestellt

Looper programmiert werden. Thread über mehrere Schritte

  1. Erweitern Sie Thread

  2. Rufen Sie an. Looper.prepare() zu initialisieren, um Thread als Looper

  3. Erstellen Sie eine oder mehrere Handler (s) zur Verarbeitung der eingehenden Nachrichten

  4. Rufen Sie an. Looper.loop() Nachrichten zu verarbeiten, bis die Schleife angewiesen wird quit() .

7voto

Ravindra babu Punkte 45577

Lebensdauer von java Thema ist nach Abschluss von run() Methode. Derselbe Thread kann nicht erneut gestartet werden.

Looper wandelt normal Thread in eine Nachrichtenschleife. Die wichtigsten Methoden der Looper sind:

void prepare ()

Initialisierung des aktuellen Threads als Looper. Dies gibt Ihnen die Möglichkeit, Handler zu erstellen, die dann auf diesen Looper verweisen, bevor Sie die Schleife tatsächlich starten. Rufen Sie nach dem Aufruf dieser Methode unbedingt loop() auf und beenden Sie sie durch den Aufruf von quit().

void loop ()

Führen Sie die Nachrichtenwarteschlange in diesem Thread aus. Stellen Sie sicher, dass Sie quit() aufrufen, um die Schleife zu beenden.

void quit()

Beendet den Looper.

Bewirkt, dass die Methode loop() beendet wird, ohne weitere Nachrichten in der Nachrichtenwarteschlange zu verarbeiten.

Este mindorks-Artikel von Janishar erklärt die Kernkonzepte auf nette Art und Weise.

enter image description here

Looper mit einem Thema verbunden ist. Wenn Sie Looper auf dem UI-Thread, Looper.getMainLooper() gibt den zugehörigen Thread zurück.

Sie benötigen Looper in Verbindung zu bringen mit einem Handler .

Looper , Handler und HandlerThread sind der Weg von Android, die Probleme der asynchronen Programmierung zu lösen.

Sobald Sie Handler können Sie die folgenden APIs aufrufen.

post (Runnable r)

Bewirkt, dass das Runnable r der Nachrichtenwarteschlange hinzugefügt wird. Die Runnable wird auf dem Thread ausgeführt, an den dieser Handler angehängt ist.

boolean sendMessage (Message msg)

Schiebt eine Nachricht an das Ende der Nachrichtenwarteschlange nach allen anstehenden Nachrichten vor der aktuellen Zeit. Sie wird in handleMessage(Message) in dem mit diesem Handler verbundenen Thread empfangen.

HandlerThread ist eine praktische Klasse zum Starten eines neuen Threads, der einen Looper hat. Der Looper kann dann verwendet werden, um Handler-Klassen zu erstellen

In einigen Szenarien können Sie nicht Runnable Aufgaben im UI-Thread. z.B. Netzwerkoperationen: Senden von Nachrichten über einen Socket, Öffnen einer URL und Abrufen des Inhalts durch Lesen InputStream

In diesen Fällen, HandlerThread nützlich ist. Sie können erhalten Looper Objekt aus HandlerThread und erstellen eine Handler en HandlerThread anstelle des Hauptthreads.

El HandlerThread Code wird wie folgt aussehen:

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

Ein Beispiel für einen Code finden Sie im folgenden Beitrag:

Android: Toast in einem Thread

5voto

TacB0sS Punkte 9806

Diese Antwort hat nichts mit der Frage zu tun, aber die Verwendung von Looper und die Art und Weise, wie die Leute den Handler und Looper in ALLEN Antworten hier erstellt haben, sind schlichtweg schlechte Praxis (einige Erklärungen sind jedoch korrekt), ich muss dies posten:

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

und für eine vollständige Umsetzung

4voto

AskNilesh Punkte 63763

Was ist Looper?

AUS DOKUMENTE

Looper

Looper Klasse zur Ausführung einer Nachrichtenschleife für eine thread . Threads sind standardmäßig nicht mit einer Nachrichtenschleife verknüpft; um eine zu erstellen, rufen Sie prepare() in dem Thread, der die Schleife ausführen soll, und dann loop() um Nachrichten zu verarbeiten, bis die Schleife gestoppt wird.

  • A Looper ist eine Nachrichtenverarbeitungsschleife:
  • Eine wichtige Eigenschaft von Looper ist, dass sie mit dem Thread verbunden ist, in dem der Looper erstellt wird
  • Die Klasse Looper verwaltet eine MessageQueue , die eine Liste von Nachrichten enthält. Ein wichtiges Merkmal des Loopers ist, dass er mit dem Thread verbunden ist, in dem der Looper erstellt wird.
  • El Looper heißt so, weil es die Schleife implementiert - es nimmt die nächste Aufgabe, führt sie aus, nimmt dann die nächste und so weiter. Die Handler wird Handler genannt, weil niemand einen besseren Namen erfinden konnte
  • Android Looper ist eine Java-Klasse innerhalb der Android-Benutzeroberfläche, die zusammen mit der Handler-Klasse UI-Ereignisse wie Schaltflächenklicks, Bildschirmneubildungen und Ausrichtungswechsel verarbeitet.

Wie funktioniert das?

enter image description here

Looper erstellen

Ein Thread erhält eine Looper y MessageQueue durch den Aufruf Looper.prepare() nach seiner Ausführung. Looper.prepare() identifiziert den aufrufenden Thread, erstellt einen Looper und MessageQueue Objekt und verknüpfen Sie den Thread

MUSTERCODE

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();
      } 
  }

Weitere Informationen finden Sie im folgenden Beitrag

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X