Zugriff auf den UI-Thread-Handler über einen Dienst

89

Ich versuche etwas Neues auf Android, für das ich auf den Handler des UI-Threads zugreifen muss.

Ich kenne folgendes:

  1. Der UI-Thread verfügt über einen eigenen Handler und Looper
  2. Jede Nachricht wird in die Nachrichtenwarteschlange des UI-Threads gestellt
  3. Der Looper nimmt das Ereignis auf und gibt es an den Handler weiter
  4. Der Handler verarbeitet die Nachricht und sendet das spezifische Ereignis an die Benutzeroberfläche

Ich möchte meinen Dienst haben, der den UI-Thread-Handler abrufen und eine Nachricht in diesen Handler einfügen muss. Damit diese Nachricht verarbeitet und an die Benutzeroberfläche ausgegeben wird. Hier ist der Dienst ein normaler Dienst, der von einer Anwendung gestartet wird.

Ich würde gerne wissen, ob dies möglich ist. Wenn ja, schlagen Sie bitte einige Codefragmente vor, damit ich es versuchen kann.

Grüße Girish

iLikeAndroid
quelle

Antworten:

179

Dieser Codeausschnitt erstellt einen Handler, der dem Hauptthread (UI) zugeordnet ist:

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

Sie können dann Dinge zur Ausführung im Hauptthread (UI) wie folgt posten:

handler.post(runnable_to_call_from_main_thread);

Wenn der Handler selbst aus dem Hauptthread (UI) erstellt wird, kann das Argument der Kürze halber weggelassen werden:

Handler handler = new Handler();

Das Android Dev Führer auf Prozesse und Threads hat weitere Informationen.

Volley
quelle
2
Getestet und es funktioniert super! Ein Beispiel für einen Anwendungsfall: Ich habe eine Weboberfläche, die von einem Server bereitgestellt wird, der direkt auf dem Gerät ausgeführt wird. Da die Schnittstelle zur direkten Interaktion mit der Benutzeroberfläche verwendet werden kann und der Server auf einem eigenen Thread ausgeführt werden muss, musste der UI-Thread von außerhalb einer Aktivität berührt werden. Die von Ihnen beschriebene Methode hat hervorragend funktioniert.
MrPjer
1
Brillant. Funktioniert wie ein Zauber und ist sehr nützlich. DANKE.
JRun
perfect ^^ habe es gerade benutzt, um meine UI von einem StreamingService zu aktualisieren. genau das was ich brauchte danke!
An-Droide
Wissen Sie, ob ich eine Singleton-Instanz eines Handlers erstellen und diese jedes Mal verwenden kann, wenn ich etwas auf dem UI-Thread ausführen muss?
HelloWorld
Ich denke, wir werden es nie erfahren
Denny
28

Erstellen Sie ein Messengeran Ihr angehängtes Objekt Handlerund übergeben Sie es Messengeran das Service(z. B. in einem IntentExtra für startService()). Das Servicekann dann ein senden , Messageum die Handlerüber die Messenger. Hier ist eine Beispielanwendung, die dies demonstriert.

CommonsWare
quelle
Danke für diesen Tipp. Das war hilfreich. Im folgenden Stapel finden Sie einen Touch-Ereignisfluss zu meiner Aktivität MyDemo.dispatchTouchEvent (MotionEvent) -Zeile: 20 PhoneWindow $ DecorView.dispatchTouchEvent (MotionEvent) -Zeile: 1696 ViewRoot.handleMessage (Message) -Zeile: 1658 ViewRoot (Handler) .dispatchMessage (Message) ) line: 99 Looper.loop () line: 123 // Die Ereignisbehandlung beginnt hier. ActivityThread.main (String []) line: 4203 Hier ist ViewRoot ein Handler. Ich möchte die Referenz dieses Handlers erhalten ... ist es möglich, diese aus meiner Anwendung zu erhalten?
iLikeAndroid
@iLikeAndroid: Wenn Sie das nicht erstellt haben Handler, können Sie nicht darauf zugreifen, AFAIK.
CommonsWare
Danke dir. Ich habe versucht, eine Instanz von ViewRoot zu erstellen. Dies ist nichts als ein Handler. Jetzt kann ich die Nachrichten auf diesem Handler ausgeben. Der Handler erhält die Nachricht. Der ViewRoot kann die Nachricht jedoch nicht verarbeiten, da sie nicht ordnungsgemäß initialisiert wurde. Ich muss ViewRoot.setView () aufrufen, um die richtigen Daten für ViewRoot zu initialisieren. Ich möchte wissen, ob es eine Standardansicht oder eine Basisansicht usw. gibt, die ich zum Initialisieren verwenden kann.
iLikeAndroid
@iLikeAndroid: Es gibt keine ViewRootim Android SDK, AFAICT.
CommonsWare
1
@ hadez30: Ich persönlich benutze gebundene Dienste nicht viel. Sie können immer noch ein Handler/ verwenden Messenger, obwohl ich all das durch einen Eventbus ersetzen würde (z. B. den EventBus von greenrobot).
CommonsWare
4

Im Moment bevorzuge ich die Verwendung von Eventbusbibliotheken wie Otto für diese Art von Problem. Abonnieren Sie einfach die gewünschten Komponenten (Aktivität):

protected void onResume() {
    super.onResume();
    bus.register(this);
}

Geben Sie dann eine Rückrufmethode an:

public void onTimeLeftEvent(TimeLeftEvent ev) {
    // process event..
}

und dann, wenn Ihr Dienst eine Anweisung wie folgt ausführt:

bus.post(new TimeLeftEvent(340));

Dieses POJO wird an Ihre oben genannte Aktivität und alle anderen abonnierenden Komponenten weitergegeben. Einfach und elegant.

Kinderwagen
quelle
3

Ich schlage vor, folgenden Code zu versuchen:

    new Handler(Looper.getMainLooper()).post(() -> {

        //UI THREAD CODE HERE



    });
user2983041
quelle
Einige zusätzliche Erklärungen sind erforderlich, um das OP zu unterstützen.
Moog
2

Sie können Werte über den Broadcast-Empfänger abrufen ...... wie folgt: Erstellen Sie zunächst Ihren eigenen IntentFilter als,

Intent intentFilter=new IntentFilter();
intentFilter.addAction("YOUR_INTENT_FILTER");

Erstellen Sie dann den BroadcastReceiver der inneren Klasse als:

    private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
    /** Receives the broadcast that has been fired */
    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent.getAction()=="YOUR_INTENT_FILTER"){
           //HERE YOU WILL GET VALUES FROM BROADCAST THROUGH INTENT EDIT YOUR TEXTVIEW///////////
           String receivedValue=intent.getStringExtra("KEY");
        }
    }
};

Registrieren Sie jetzt Ihren Rundfunkempfänger in onResume () als,

registerReceiver(broadcastReceiver, intentFilter);

Und schließlich entfernen Sie die Registrierung von BroadcastReceiver in onDestroy () als,

unregisterReceiver(broadcastReceiver);

Jetzt der wichtigste Teil ... Sie müssen die Sendung von jedem Ort aus starten, an dem Sie Werte senden müssen.

Intent i=new Intent();
i.setAction("YOUR_INTENT_FILTER");
i.putExtra("KEY", "YOUR_VALUE");
sendBroadcast(i);

....Prost :)

Melbourne Lopes
quelle
1

So kotlinkönnen Sie es machen

Angenommen, Sie möchten eine Toast-Nachricht vom Dienst anzeigen

val handler = Handler(Looper.getMainLooper())
handler.post {
   Toast.makeText(context, "This is my message",Toast.LENGTH_LONG).show()
}
Zohab Ali
quelle
0

Lösung:

  1. Erstellen Sie einen Handler mit Looper aus dem Hauptthread: requestHandler
  2. Erstellen Sie eine Handlerwith Looperfrom Main Thread: responseHandler- und override- handleMessageMethode
  3. Veröffentlichen Sie eine ausführbare Aufgabe auf requestHandler
  4. RunnableRufen Sie innerhalb der Task sendMessage für responseHandler auf
  5. Dieser sendMessageErgebnisaufruf von handleMessage in responseHandler.
  6. Holen Sie sich Attribute aus dem Messageund verarbeiten Sie es, aktualisieren Sie die Benutzeroberfläche

Beispielcode:

    /* Handler from UI Thread to send request */

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

     /* Handler from UI Thread to process messages */

    final Handler responseHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {

            /* Processing handleMessage */

            Toast.makeText(MainActivity.this,
                    "Runnable completed with result:"+(String)msg.obj,
                    Toast.LENGTH_LONG)
                    .show();
        }
    };

    for ( int i=0; i<10; i++) {
        Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                try {
                   /* Send an Event to UI Thread through message. 
                      Add business logic and prepare message by 
                      replacing example code */

                    String text = "" + (++rId);
                    Message msg = new Message();

                    msg.obj = text.toString();
                    responseHandler.sendMessage(msg);
                    System.out.println(text.toString());

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