In einem Android-Dienst habe ich Threads für Hintergrundaufgaben erstellt.
Ich habe eine Situation, in der ein Thread bestimmte Aufgaben in der Nachrichtenwarteschlange des Hauptthreads veröffentlichen muss, z. B. a Runnable
.
Gibt es einen Weg , um Handler
von dem Hauptthread und Post Message
/ Runnable
um es von meinem anderen Thread?
Vielen Dank,
Antworten:
HINWEIS: Diese Antwort hat so viel Aufmerksamkeit erhalten, dass ich sie aktualisieren muss. Seit die ursprüngliche Antwort veröffentlicht wurde, hat der Kommentar von @dzeikei fast genauso viel Aufmerksamkeit erhalten wie die ursprüngliche Antwort. Hier sind also 2 mögliche Lösungen:
1. Wenn Ihr Hintergrund-Thread einen Verweis auf ein
Context
Objekt hat:Stellen Sie sicher, dass Ihre Hintergrund-Worker-Threads Zugriff auf ein Kontextobjekt haben (dies kann der Anwendungskontext oder der Dienstkontext sein). Dann machen Sie dies einfach im Hintergrund-Worker-Thread:
2. Wenn Ihr Hintergrund-Thread kein
Context
Objekt hat (oder benötigt)(vorgeschlagen von @dzeikei):
quelle
Handler
(oder eineHandler.Callback
Schnittstelle) verwenden, wird IhrehandleMessage()
Methode NUR für Nachrichten aufgerufen, die mit Ihrem Handler veröffentlicht wurden. Der Hauptthread verwendet einen anderen Handler zum Posten / Verarbeiten von Nachrichten, sodass kein Konflikt besteht.Handler mainHandler = new Handler(Looper.getMainLooper());
new Runnable(){@Override public void run() {....}};
Wie ein Kommentator unten richtig betonte, ist dies keine allgemeine Lösung für Dienste, sondern nur für Threads, die von Ihrer Aktivität aus gestartet wurden (ein Dienst kann ein solcher Thread sein, aber nicht alle sind dies). Lesen Sie zum komplizierten Thema der Kommunikation zwischen Service und Aktivität den gesamten Abschnitt "Services" des offiziellen Dokuments - es ist komplex, daher lohnt es sich, die Grundlagen zu verstehen: http://developer.android.com/guide/components/services.html #Benachrichtigungen
Die folgende Methode kann in einfachsten Fällen funktionieren.
Wenn ich Sie richtig verstehe, muss Code im GUI-Thread der Anwendung ausgeführt werden (ich kann mir nichts anderes vorstellen, das als "Haupt" -Thread bezeichnet wird). Hierfür gibt es eine Methode
Activity
:Doc: http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29
Hoffe das ist was du suchst.
quelle
Service
. Sie können nichtrunOnUiThread()
in einem verwendenService
. Diese Antwort ist irreführend und geht nicht auf die gestellte Frage ein.Es gibt einen anderen einfachen Weg, wenn Sie keinen Zugriff auf den Kontext haben.
1). Erstellen Sie einen Handler aus dem Haupt-Looper:
2). Implementieren Sie eine ausführbare Schnittstelle:
3). Poste dein Runnable an den uiHandler:
Das ist alles ;-) Viel Spaß mit Threads, aber vergiss nicht, sie zu synchronisieren.
quelle
Wenn Sie Code in einem Thread ausführen, z. B. eine Aktion verzögern, müssen Sie ihn
runOnUiThread
aus dem Kontext aufrufen . Wenn sich Ihr Code beispielsweise innerhalb derMainActivity
Klasse befindet, verwenden Sie Folgendes:Wenn Ihre Methode entweder vom Hauptthread (UI-Thread) oder von anderen Threads aus aufgerufen werden kann, müssen Sie Folgendes überprüfen:
quelle
Service
. Sie können nichtrunOnUiThread()
in einem verwendenService
.Activity
Dokumentation angegeben haben,runOnUiThread()
ist eine Methode vonActivity
. Es ist keine Methode vonService
, daher können Sie es nicht verwenden. Was könnte klarer sein als das?Ein komprimierter Codeblock lautet wie folgt:
Dies beinhaltet nicht die Weitergabe der Aktivitätsreferenz oder der Anwendungsreferenz.
Kotlin-Äquivalent:
quelle
Kotlin-Versionen
Wenn Sie an einer Aktivität teilnehmen , verwenden Sie
Wenn Sie einen Aktivitätskontext haben , verwenden Sie mContext
Wenn Sie sich an einem Ort befinden, an dem kein Kontext verfügbar ist , verwenden Sie
quelle
runOnUiThread(){...}
Der einfachste Weg, insbesondere wenn Sie keinen Kontext haben, wenn Sie RxAndroid verwenden, können Sie Folgendes tun:
quelle
Genauerer Kotlin-Code mit dem Handler:
quelle
Eine Methode, die ich mir vorstellen kann, ist folgende:
1) Lassen Sie die Benutzeroberfläche an den Dienst binden.
2) Stellen Sie eine Methode wie die folgende bereit, mit der Sie Folgendes
Binder
registrierenHandler
:3) Rufen Sie im UI-Thread die obige Methode auf, nachdem Sie an den Dienst gebunden haben:
4) Verwenden Sie den Handler im Thread des Dienstes, um Ihre Aufgabe zu veröffentlichen:
quelle
HandlerThread
ist eine bessere Option für normale Java-Threads in Android.requestHandler
post
eineRunnable
Aufgabe aufrequestHandler
Kommunikation mit UI-Thread von
HandlerThread
Handler
mitLooper
for for main thread:responseHandler
und überschreiben Sie siehandleMessage
Runnable
Aufgabe eines anderen Threads (HandlerThread
in diesem Fall)sendMessage
aufresponseHandler
sendMessage
Ergebnisaufruf vonhandleMessage
inresponseHandler
.Message
und verarbeiten Sie es, aktualisieren Sie die BenutzeroberflächeBeispiel : Aktualisierung
TextView
mit Daten, die von einem Webdienst empfangen wurden. Da der Webdienst für einen Nicht-UI-Thread aufgerufen werden sollte, derHandlerThread
für den Netzwerkbetrieb erstellt wurde. Sobald Sie den Inhalt vom Webdienst erhalten haben, senden Sie eine Nachricht an Ihren Handler für den Hauptthread (UI-Thread)Handler
behandelt die Nachricht und aktualisiert die Benutzeroberfläche.Beispielcode:
Nützliche Artikel:
Handlerthreads-und-warum-Sie-sollten-sie-in-Ihren-Android-Apps verwenden
android-looper-handler-handlerthread-i
quelle
Ich weiß, dass dies eine alte Frage ist, aber ich bin auf einen Einzeiler mit Hauptthread gestoßen, den ich sowohl in Kotlin als auch in Java verwende. Dies ist möglicherweise nicht die beste Lösung für einen Dienst, aber für den Aufruf von etwas, das die Benutzeroberfläche innerhalb eines Fragments verändert, ist dies äußerst einfach und offensichtlich.
Java (8):
Kotlin:
quelle
Folgen Sie dieser Methode. Auf diese Weise können Sie die Benutzeroberfläche einfach über einen Hintergrund-Thread aktualisieren. runOnUiThread arbeitet am Hauptthread (UI). Ich denke, dieses Code-Snippet ist weniger komplex und einfach, besonders für Anfänger.
im Falle einer Dienstleistung
Erstellen Sie einen Handler in oncreate
dann benutze es so
quelle
Für Kotlin können Sie Anko-Corountines verwenden :
aktualisieren
veraltet
quelle
Am praktischsten ist es also, Folgendes zu tun:
Und danach:
quelle
Dies kann auch in einer Serviceklasse ohne Probleme funktionieren.
quelle
Bei Kotlin ist es in jeder Funktion genauso:
quelle
Activity
.