it-swarm.com.de

Laufender Code im Haupt-Thread von einem anderen Thread

In einem Android-Dienst habe ich einen oder mehrere Threads für Hintergrundaufgaben erstellt. 

Ich habe eine Situation, in der ein Thread eine bestimmte Aufgabe in der Nachrichtenwarteschlange des Haupt-Threads bereitstellen muss, beispielsweise eine Runnable.

Gibt es eine Möglichkeit, Handler des Hauptthreads zu erhalten und Message/Runnable aus meinem anderen Thread zu senden?

Vielen Dank, 

265
Ahmed

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 zwei mögliche Lösungen:

1. Wenn dein Hintergrund-Thread einen Verweis auf ein Context-Objekt hat:

Stellen Sie sicher, dass Ihre Hintergrund-Worker-Threads Zugriff auf ein Context-Objekt haben (dies kann der Anwendungskontext oder der Dienstkontext sein). Dann mache es einfach im Hintergrund-Worker-Thread:

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(context.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);

2. Wenn dein Hintergrund-Thread kein Context-Objekt hat (oder benötigt)

(vorgeschlagen von @dzeikei):

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(Looper.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);
542
David Wasser

Wie ein Kommentator unten richtig dargelegt hat, ist dies keine allgemeine Lösung für Services, sondern nur für Threads, die von Ihrer Aktivität aus gestartet werden (ein Service kann ein solcher Thread sein, aber nicht alle sind es). Zum komplizierten Thema Service. Aktivitätskommunikation Bitte lesen Sie den gesamten Abschnitt "Services" des offiziellen Dokuments - es ist komplex und es ist daher wichtig, die Grundlagen zu verstehen: http://developer.Android.com/guide/components/services.html#Notifications

Die folgende Methode funktioniert möglicherweise in einfachsten Fällen.

Wenn ich Sie richtig verstehe, benötigen Sie etwas Code, der im GUI-Thread der Anwendung ausgeführt werden soll (kann nicht an etwas anderes denken, das als "main" -Thread bezeichnet wird). Dafür gibt es eine Methode in Activity:

someActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
           //Your code to run in GUI thread here
        }//public void run() {
});

Doc: http://developer.Android.com/reference/Android/app/Activity.html#runOnUiThread%28Java.lang.Runnable%29

Hoffe, das ist es, wonach du suchst.

125

Es gibt einen anderen einfachen Weg, wenn Sie keinen Zugriff auf den Kontext haben.

1). Erstellen Sie einen Handler aus dem Haupt-Looper:

Handler uiHandler = new Handler(Looper.getMainLooper());

2). Implementieren Sie eine ausführbare Schnittstelle:

Runnable runnable = new Runnable() { // your code here }

3). Posten Sie Ihren Runable an den uiHandler:

uiHandler.post(runnable);

Das ist alles ;-) Viel Spaß mit Threads, aber vergiss nicht, sie zu synchronisieren.

28
tema_man

Wenn Sie Code in einem Thread ausführen, z. Wenn Sie eine Aktion verzögern, müssen Sie runOnUiThread aus dem Kontext aufrufen. Wenn sich Ihr Code beispielsweise in der Klasse MainActivity befindet, verwenden Sie Folgendes:

MainActivity.this.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        myAction();
    }
});

Wenn Ihre Methode entweder von main (UI-Thread) oder von anderen Threads aufgerufen werden kann, müssen Sie Folgendes prüfen:

public void myMethod() {
   if( Looper.myLooper() == Looper.getMainLooper() ) {
       myAction();
   }
   else {

}
26

Ein komprimierter Codeblock lautet wie folgt:

   new Handler(Looper.getMainLooper()).post(new Runnable() {
       @Override
       public void run() {
           // things to do on the main thread
       }
   });

Dies beinhaltet nicht die Weitergabe der Aktivitätsreferenz oder der Anwendungsreferenz.

Kotlin-Äquivalent:

    Handler(Looper.getMainLooper()).post(Runnable {
        // things to do on the main thread
    })
13
david m lee

Kotlin-Versionen

Wenn Sie sind in einer Aktivität, dann verwenden Sie

runOnUiThread {
    //code that runs in main
}

Wenn Sie haben Aktivitätskontext, dann verwenden Sie mContext

mContext.runOnUiThread {
    //code that runs in main
}

Wenn Sie sich an einem Ort befinden, an dem kein Kontext verfügbar, verwenden Sie

Handler(Looper.getMainLooper()).post {  
    //code that runs in main
}
4

Eine Methode, die mir einfällt, ist folgende:

1) Lassen Sie die Benutzeroberfläche an den Dienst binden.
2) Machen Sie eine Methode wie die unten stehende durch die Binder sichtbar, die Ihre Handler registriert:

public void registerHandler(Handler handler) {
    mHandler = handler;
}

3) Rufen Sie im UI-Thread die obige Methode nach dem Binden an den Dienst auf:

mBinder.registerHandler(new Handler());

4) Verwenden Sie den Handler im Service-Thread, um Ihre Aufgabe zu posten:

mHandler.post(runnable);
4
Dheeraj V.S.

Ich weiß, dass dies eine alte Frage ist, aber ich bin auf einen Main-Thread-Einzeiler 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. Wenn Sie jedoch etwas aufrufen, das die Benutzeroberfläche innerhalb eines Fragments ändert, ist dies äußerst einfach und offensichtlich.

Java (8):

 getActivity().runOnUiThread(()->{
      //your main thread code
 });

Kotlin:

this.runOnUiThread {
     //your main thread code
}
2
mevdev

HandlerThread ist eine bessere Option für normale Java-Threads in Android.

  1. Erstellen Sie ein HandlerThread und starten Sie es
  2. Erstellen Sie einen Handler mit Looper aus HandlerThread: requestHandler
  3. post eine Runnable-Task auf requestHandler

Kommunikation mit UI-Thread von HandlerThread

  1. Erstellen Sie eine Handler mit Looper für den Haupt-Thread: responseHandler und überschreiben Sie die handleMessage-Methode
  2. Rufen Sie in der Runnable-Task eines anderen Threads (in diesem Fall HandlerThread) sendMessage für responseHandler auf.
  3. Dieser sendMessage Ergebnisaufruf von handleMessage in responseHandler.
  4. Holen Sie sich Attribute aus der Variablen Message und verarbeiten Sie sie, aktualisieren Sie die Benutzeroberfläche

Beispiel: Aktualisieren Sie TextView mit Daten, die von einem Webservice empfangen wurden. Da der Webdienst in einem Nicht-UI-Thread aufgerufen werden muss, wurde HandlerThread für den Netzwerkbetrieb erstellt. Wenn Sie den Inhalt vom Webdienst abrufen, senden Sie die Nachricht an Ihren Haupt-Thread-Handler (UI-Thread) und Handler wird die Nachricht verarbeiten und die Benutzeroberfläche aktualisieren.

Beispielcode:

HandlerThread handlerThread = new HandlerThread("NetworkOperation");
handlerThread.start();
Handler requestHandler = new Handler(handlerThread.getLooper());

final Handler responseHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        txtView.setText((String) msg.obj);
    }
};

Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        try {
            Log.d("Runnable", "Before IO call");
            URL page = new URL("http://www.your_web_site.com/fetchData.jsp");
            StringBuffer text = new StringBuffer();
            HttpURLConnection conn = (HttpURLConnection) page.openConnection();
            conn.connect();
            InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
            BufferedReader buff = new BufferedReader(in);
            String line;
            while ((line = buff.readLine()) != null) {
                text.append(line + "\n");
            }
            Log.d("Runnable", "After IO call:"+ text.toString());
            Message msg = new Message();
            msg.obj = text.toString();
            responseHandler.sendMessage(msg);


        } catch (Exception err) {
            err.printStackTrace();
        }
    }
};
requestHandler.post(myRunnable);

Nützliche Artikel:

Handlerthreads und warum sollten Sie sie in Ihren Android-Apps verwenden

Android-Greifer-Handler-Handlerthread-i

2
Ravindra babu

Der einfachste Weg, insbesondere wenn Sie keinen Kontext haben, wenn Sie RxAndroid verwenden, können Sie Folgendes tun:

AndroidSchedulers.mainThread().scheduleDirect {
    runCodeHere()
}
2
Inn0vative1

Genauerer Kotlin-Code mit Handler:

Handler(Looper.getMainLooper()).post {  
 // your codes here run on main Thread
 }
1
Hamed Jaliliani

Folgen Sie dieser Methode. Auf diese Weise können Sie die Benutzeroberfläche einfach von einem Hintergrund-Thread aus aktualisieren. runOnUiThread funktioniert auf dem Haupt- (UI) -Thread. Ich denke, dieses Code-Snippet ist weniger komplex und einfach, besonders für Anfänger.

AsyncTask.execute(new Runnable() {
            @Override
            public void run() {

            //code you want to run on the background
            someCode();

           //the code you want to run on main thread
 MainActivity.this.runOnUiThread(new Runnable() {

                    public void run() {

/*the code you want to run after the background operation otherwise they will executed earlier and give you an error*/
                        executeAfterOperation();

                   }
                });
            }
        });

im Falle einer Dienstleistung

erstellen Sie einen Handler im oncreate

 handler = new Handler();

dann verwenden Sie es so

 private void runOnUiThread(Runnable runnable) {
        handler.post(runnable);
    }
1
MarGin
public void mainWork() {
    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            //Add Your Code Here
        }
    });
}

Dies kann auch in einer Serviceklasse ohne Probleme funktionieren.

0
NUSKTECsoft

für Kotlin können Sie Anko Corountines verwenden:

update

doAsync {
   ...
}

veraltet 

async(UI) {
    // Code run on UI thread
    // Use ref() instead of [email protected]
}
0
Francis