Acceder al controlador de subprocesos de la interfaz de usuario desde un servicio


90

Estoy probando algo nuevo en Android para lo cual necesito acceder al controlador del hilo de la interfaz de usuario.

Yo se lo siguiente:

  1. El hilo de la interfaz de usuario tiene su propio controlador y looper
  2. Cualquier mensaje se colocará en la cola de mensajes del hilo de la interfaz de usuario
  3. El looper recoge el evento y se lo pasa al controlador.
  4. El controlador maneja el mensaje y envía el evento específico a la interfaz de usuario

Quiero tener mi servicio que debe obtener el controlador de subprocesos de la interfaz de usuario y poner un mensaje en este controlador. Para que este mensaje se procese y se envíe a la interfaz de usuario. Aquí el servicio será un servicio normal que será iniciado por alguna aplicación.

Me gustaría saber si esto es posible. Si es así, sugiera algunos fragmentos de código para que pueda probarlo.

Saludos Girish

Respuestas:


179

Este fragmento de código construye un controlador asociado con el hilo principal (UI):

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

Luego puede publicar cosas para su ejecución en el hilo principal (UI) de la siguiente manera:

handler.post(runnable_to_call_from_main_thread);

Si el controlador en sí se crea a partir del hilo principal (UI), el argumento se puede omitir por brevedad:

Handler handler = new Handler();

La Guía para desarrolladores de Android sobre procesos e hilos tiene más información.


2
¡Lo probé y funciona muy bien! Un ejemplo de un caso de uso: tengo una interfaz web que está siendo servida por un servidor que se ejecuta directamente en el dispositivo. Dado que la interfaz se puede usar para interactuar directamente con la interfaz de usuario, y dado que el servidor debe ejecutarse en su propio hilo, necesitaba una forma de tocar el hilo de la interfaz de usuario desde fuera de una actividad. El método que ha descrito funcionó muy bien.
mrPjer

1
Brillante. Funciona a las mil maravillas y es muy útil. GRACIAS.
JRun

perfect ^^ solo lo usé para actualizar mi interfaz de usuario desde un StreamingService. exactamente lo que necesitaba gracias!
An-droide

¿Sabes si puedo crear una instancia singleton de un controlador y usarla cada vez que necesito ejecutar algo en el hilo de la interfaz de usuario?
HelloWorld

Supongo que nunca lo sabremos
Denny

28

Cree un Messengerobjeto adjunto a su Handlery páselo Messengeral Service(por ejemplo, en un Intentextra para startService()). A Servicecontinuación, puede enviar un mensaje Messagea Handlertravés de Messenger. Aquí hay una aplicación de muestra que demuestra esto.


Gracias por este consejo. Esto fue útil. Consulte la siguiente pila para ver un flujo de evento táctil a mi actividad Línea MyDemo.dispatchTouchEvent (MotionEvent): 20 PhoneWindow $ DecorView.dispatchTouchEvent (MotionEvent) línea: 1696 ViewRoot.handleMessage (Message) línea: 1658 ViewRoot (Handler) .dispatchMessage (Message ) línea: 99 Looper.loop () línea: 123 // El manejo de eventos comienza aquí ActivityThread.main (String []) línea: 4203 Aquí ViewRoot es un manejador. Quiero obtener la referencia de este controlador ... ¿es posible obtener esto de mi aplicación?
iLikeAndroid

@iLikeAndroid: Si no creó el Handler, no puede acceder a él, AFAIK.
CommonsWare

Gracias. Intenté crear una instancia de ViewRoot. Esto no es más que un manejador. Ahora puedo emitir los mensajes en este controlador. El manejador está recibiendo el mensaje. Pero ViewRoot no puede procesar el mensaje porque no se inicializó correctamente. Necesito llamar a ViewRoot.setView () para inicializar los datos adecuados en ViewRoot. Quiero saber si hay una vista predeterminada o una vista base, etc., que puedo usar para inicializar.
iLikeAndroid

@iLikeAndroid: no hay ViewRooten el SDK de Android, AFAICT.
CommonsWare

1
@ hadez30: Personalmente, no uso mucho los servicios vinculados. Aún puedes usar un Handler/ Messenger, aunque reemplazaría todo eso con un bus de eventos (por ejemplo, EventBus de greenrobot).
CommonsWare

4

Por el momento, prefiero usar una biblioteca de bus de eventos como Otto para este tipo de problema. Simplemente suscriba los componentes deseados (actividad):

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

Luego proporcione un método de devolución de llamada:

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

y luego, cuando su servicio ejecute una declaración como esta:

bus.post(new TimeLeftEvent(340));

Ese POJO se transferirá a su actividad anterior y a todos los demás componentes de suscripción. Simple y elegante.


3

Sugiero probar el siguiente código:

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

        //UI THREAD CODE HERE



    });

Se requiere alguna explicación adicional para ayudar al OP.
Moog

2

Puede obtener valores a través del receptor de transmisión ... de la siguiente manera, primero cree su propio IntentFilter como,

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

Luego cree la clase interna BroadcastReceiver como,

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

Ahora registre su receptor de transmisión en onResume () como,

registerReceiver(broadcastReceiver, intentFilter);

Y finalmente Anular el registro de BroadcastReceiver en onDestroy () como,

unregisterReceiver(broadcastReceiver);

Ahora la parte más importante ... Necesitas disparar la transmisión desde donde necesites enviar valores ..... así que haz lo,

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

....salud :)


1

En kotlinesa es la forma que puede hacerlo

Digamos si desea mostrar el mensaje Toast del servicio

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

0

Solución:

  1. Cree un controlador con Looper desde el hilo principal: requestHandler
  2. Cree un método Handlercon Looperdesde Main Thread: responseHandler y overridehandleMessage
  3. publicar un Ejecutable de trabajo sobre RequestHandler
  4. Dentro de la Runnabletarea, llame a sendMessage en responseHandler
  5. Esta sendMessageinvocación de resultado de handleMessage en responseHandler.
  6. Obtener atributos del Messagey procesarlo, actualizar la interfaz de usuario

Código de muestra:

    /* 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);
    }
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.