Accesso al gestore thread dell'interfaccia utente da un servizio


89

Sto provando qualcosa di nuovo su Android per il quale ho bisogno di accedere al gestore del thread dell'interfaccia utente.

So quanto segue:

  1. Il thread dell'interfaccia utente ha il proprio gestore e looper
  2. Qualsiasi messaggio verrà inserito nella coda dei messaggi del thread dell'interfaccia utente
  3. Il looper raccoglie l'evento e lo passa al gestore
  4. Il gestore gestisce il messaggio e invia l'evento specifico all'interfaccia utente

Voglio avere il mio servizio che deve ottenere il gestore del thread dell'interfaccia utente e inserire un messaggio in questo gestore. In modo che questo messaggio verrà elaborato e verrà inviato all'interfaccia utente. Qui il servizio sarà un normale servizio che verrà avviato da qualche applicazione.

Vorrei sapere se questo è possibile. In tal caso, suggerisci alcuni frammenti di codice, in modo che io possa provarlo.

Saluti Girish

Risposte:


179

Questo frammento di codice costruisce un gestore associato al thread principale (UI):

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

Puoi quindi pubblicare materiale per l'esecuzione nel thread principale (UI) in questo modo:

handler.post(runnable_to_call_from_main_thread);

Se il gestore stesso viene creato dal thread principale (UI), l'argomento può essere omesso per brevità:

Handler handler = new Handler();

La guida per sviluppatori Android su processi e thread contiene ulteriori informazioni.


2
L'ho provato e funziona benissimo! Un esempio di un caso d'uso: ho un'interfaccia web che viene servita da un server in esecuzione direttamente sul dispositivo. Poiché l'interfaccia può essere utilizzata per interagire direttamente con l'interfaccia utente e poiché il server deve essere eseguito sul proprio thread, avevo bisogno di un modo per toccare il thread dell'interfaccia utente dall'esterno di un'attività. Il metodo che hai descritto ha funzionato alla grande.
mrPjer

1
Brillante. Funziona come un fascino e molto utile. GRAZIE.
JRun

perfetto ^^ l'ho appena usato per aggiornare la mia interfaccia utente da un StreamingService. esattamente quello di cui avevo bisogno grazie!
An-droide

sai se posso creare un'istanza singleton di un gestore e utilizzarla ogni volta che devo eseguire qualcosa sul thread dell'interfaccia utente?
HelloWorld

Immagino che non lo sapremo mai
Denny

28

Crea un Messengeroggetto attaccato al tuo Handlere passalo Messengeral Service(ad esempio, in un Intentextra per startService()). L' Servicepuò quindi inviare un Messageal Handlervia Messenger. Ecco un'applicazione di esempio che lo dimostra.


Grazie per questo suggerimento. Questo è stato utile. Si prega di consultare il seguente stack per un flusso di eventi di tocco alla mia attività MyDemo.dispatchTouchEvent (MotionEvent) riga: 20 PhoneWindow $ DecorView.dispatchTouchEvent (MotionEvent) riga: 1696 ViewRoot.handleMessage (Message) riga: 1658 ViewRoot (Handler) .dispatchMessage (Message ) riga: 99 Looper.loop () riga: 123 // La gestione degli eventi inizia qui ActivityThread.main (String []) riga: 4203 Qui ViewRoot è un gestore. Voglio ottenere il riferimento di questo gestore ... è possibile ottenerlo dalla mia applicazione?
iLikeAndroid

@iLikeAndroid: Se non hai creato il Handler, non puoi accedervi, AFAIK.
CommonsWare

Grazie. Ho provato a creare un'istanza di ViewRoot. Questo non è altro che un gestore. Ora sono in grado di emettere i messaggi su questo gestore. Il gestore sta ricevendo il messaggio. Ma ViewRoot non è in grado di elaborare il messaggio poiché non è inizializzato correttamente. Devo chiamare ViewRoot.setView () per inizializzare i dati corretti in ViewRoot. Voglio sapere se esiste una vista predefinita o una vista di base, ecc., Che posso usare per inizializzare?
iLikeAndroid

@iLikeAndroid: non c'è ViewRootnell'SDK Android, AFAICT.
CommonsWare

1
@ hadez30: Personalmente, non uso molto i servizi associati. Puoi ancora usare un Handler/ Messenger, anche se lo sostituirei con un bus di eventi (ad esempio, EventBus di greenrobot).
CommonsWare

4

Al momento preferisco usare la libreria di bus di eventi come Otto per questo tipo di problema. Basta iscriversi ai componenti desiderati (attività):

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

Quindi fornire un metodo di callback:

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

e poi quando il tuo servizio esegue un'istruzione come questa:

bus.post(new TimeLeftEvent(340));

Quel POJO verrà passato alla tua attività di cui sopra e a tutti gli altri componenti di sottoscrizione. Semplice ed elegante.


3

Suggerisco di provare il seguente codice:

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

        //UI THREAD CODE HERE



    });

Alcune spiegazioni aggiuntive sono necessarie per assistere l'OP.
Moog

2

È possibile ottenere valori tramite il ricevitore di trasmissione ... come segue, creare innanzitutto il proprio IntentFilter come,

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

Quindi crea BroadcastReceiver della classe interna come,

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

Ora registra il tuo ricevitore Broadcast in onResume () come,

registerReceiver(broadcastReceiver, intentFilter);

E infine Annulla la registrazione di BroadcastReceiver in onDestroy () come,

unregisterReceiver(broadcastReceiver);

Ora la parte più importante ... Devi lanciare la trasmissione da dove devi inviare valori ..... quindi fai come,

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

....Saluti :)


1

In kotlinquesto è come si può fare

Diciamo se vuoi mostrare il messaggio Toast dal servizio

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

0

Soluzione:

  1. Crea un gestore con Looper dal thread principale: requestHandler
  2. Crea un Handlercon Looperdal thread principale: responseHandler e sostituisci il handleMessagemetodo
  3. inviare un Runnable un'attività su requestHandler
  4. All'interno Runnabledell'attività, chiama sendMessage su responseHandler
  5. Questa sendMessagechiamata risultante di handleMessage in responseHandler.
  6. Ottieni attributi da Messageed elaboralo, aggiorna l'interfaccia utente

Codice di esempio:

    /* 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);
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.