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?
Antworten
Zu viele Anzeigen?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:
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.
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önnenLocalBroadcast
zu kommunizieren mitActivity
. 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 wiewhile(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.
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());
}
prepare()
muss vor der Ausführung der Ereignisschleife explizit aufgerufen werden.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 dieloop()
Methode sendet die Nachricht an ihren Ziel-Handlerquit()
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
-
Erweitern Sie
Thread
-
Rufen Sie an.
Looper.prepare()
zu initialisieren, um Thread alsLooper
-
Erstellen Sie eine oder mehrere
Handler
(s) zur Verarbeitung der eingehenden Nachrichten -
Rufen Sie an.
Looper.loop()
Nachrichten zu verarbeiten, bis die Schleife angewiesen wirdquit()
.
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.
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:
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
Was ist Looper?
AUS DOKUMENTE
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. DieHandler
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?
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
- Was ist die Beziehung zwischen Looper, Handler und MessageQueue in Android?
- Android Guts: Einführung in Looper und Handler
- Android Core verstehen: Looper, Handler und HandlerThread
- Handler in Android
- Was ist Android Looper?
- Android: Looper, Handler, HandlerThread. Teil I.
- MessageQueue und Looper in Android