Cómo hacer que el servicio de Android se comunique con la actividad

9 minutos de lectura

Como hacer que el servicio de Android se comunique con
scott saunders

Estoy escribiendo mi primera aplicación para Android y tratando de entender la comunicación entre servicios y actividades. Tengo un servicio que se ejecutará en segundo plano y realizará un registro basado en gps y tiempo. Tendré una Actividad que se utilizará para iniciar y detener el Servicio.

Entonces, primero, necesito poder averiguar si el Servicio se está ejecutando cuando se inicia la Actividad. Hay algunas otras preguntas aquí sobre eso, así que creo que puedo resolverlo (pero no dude en ofrecer consejos).

Mi verdadero problema: si la Actividad se está ejecutando y el Servicio se inicia, necesito una forma para que el Servicio envíe mensajes a la Actividad. Cadenas simples y enteros en este punto: mensajes de estado en su mayoría. Los mensajes no aparecerán regularmente, por lo que no creo que sondear el servicio sea una buena manera de hacerlo si hay otra manera. Solo quiero esta comunicación cuando el usuario haya iniciado la Actividad; no quiero iniciar la Actividad desde el Servicio. En otras palabras, si inicia la actividad y el servicio se está ejecutando, verá algunos mensajes de estado en la interfaz de usuario de la actividad cuando suceda algo interesante. Si no inicias la Actividad, no verás estos mensajes (no son tan interesantes).

Parece que debería poder determinar si el Servicio se está ejecutando y, de ser así, agregar la Actividad como oyente. Luego, elimine la actividad como oyente cuando la actividad se detenga o se detenga. ¿Es eso realmente posible? La única forma en que puedo hacerlo es hacer que la Actividad implemente Parcelable y cree un archivo AIDL para poder pasarlo a través de la interfaz remota del Servicio. Sin embargo, eso parece una exageración, y no tengo idea de cómo la Actividad debería implementar writeToParcel() / readFromParcel().

¿Hay una manera más fácil o mejor? Gracias por cualquier ayuda.

EDITAR:

Para cualquiera que esté interesado en esto más adelante, hay un código de muestra de Google para manejar esto a través de AIDL en el directorio de muestras: /apis/app/RemoteService.java

1646968751 413 Como hacer que el servicio de Android se comunique con
Máximo Cabra

El autor de la pregunta probablemente haya superado esto hace mucho tiempo, pero en caso de que alguien más busque esto…

Hay otra forma de manejar esto, que creo que podría ser la más simple.

Agrega un BroadcastReceiver a tu actividad. Regístrelo para recibir alguna intención personalizada en onResume y darlo de baja en onPause. Luego envíe esa intención desde su servicio cuando desee enviar sus actualizaciones de estado o lo que sea.

Asegúrese de que no se sentiría infeliz si alguna otra aplicación escuchara su Intent (¿alguien podría hacer algo malicioso?), pero más allá de eso, deberías estar bien.

Se solicitó una muestra de código:

En mi servicio, tengo esto:

// Do stuff that alters the content of my local SQLite Database
sendBroadcast(new Intent(RefreshTask.REFRESH_DATA_INTENT));

(RefreshTask.REFRESH_DATA_INTENT es solo una cadena constante.)

En mi actividad de escucha, defino mi BroadcastReceiver:

private class DataUpdateReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(RefreshTask.REFRESH_DATA_INTENT)) {
          // Do stuff - maybe update my view based on the changed DB contents
        }
    }
}

Declaro a mi receptor en la parte superior de la clase:

private DataUpdateReceiver dataUpdateReceiver;

anulo onResume para agregar esto:

if (dataUpdateReceiver == null) dataUpdateReceiver = new DataUpdateReceiver();
IntentFilter intentFilter = new IntentFilter(RefreshTask.REFRESH_DATA_INTENT);
registerReceiver(dataUpdateReceiver, intentFilter);

y anulo onPause para agregar:

if (dataUpdateReceiver != null) unregisterReceiver(dataUpdateReceiver);

Ahora mi actividad está escuchando mi servicio para decir “Oye, ve a actualizarte”. Podría pasar datos en el Intent en lugar de actualizar las tablas de la base de datos y luego regresar para encontrar los cambios dentro de mi actividad, pero como quiero que los cambios persistan de todos modos, tiene sentido pasar los datos a través de DB.

  • ¿Cómo? Lo que describes es exactamente lo que necesito. Pero más que eso, necesito un código de muestra completo. Gracias por adelantado. Para su información, la última vez que intenté escribir un widget, la parte de mensajería me tomó 2 meses. Ríete si quieres, pero los expertos necesitan publicar más ya que, en mi humilde opinión, ¡Android es más complicado que iOS!

    usuario407749

    27 de julio de 2011 a las 20:54


  • aaaaaaa, la Guía de desarrollo avanzado de Android de Busy Coder tiene un excelente capítulo sobre widgets. Es el único recurso que me ayudó a superar ese lío. CommonsWare, el autor, tiene una reputación de 115 000 en StackOverflow y recomiendo mucho el libro. commonsware.com/AdvAndroid

    – Cabra Máxima

    9 de agosto de 2011 a las 19:08

  • Broadcasts son fantásticos y, además, si no desea que su transmisión vaya más allá de su propio proceso, considere usar un LocalBroadcast: desarrollador.android.com/reference/android/support/v4/content/…

    – Cody Caughlan

    25 de febrero de 2012 a las 21:26

  • Gracias Cody, no había visto eso antes.

    – Cabra Máxima

    27 de febrero de 2012 a las 22:22

  • Esta es una muy buena forma de comunicación. Pero, ¿qué hacer en caso de que se entreguen resultados, cuando la actividad estaba en estado de pausa? Entonces, después de onResume, la actividad puede esperar mucho tiempo para obtener resultados. Y no se recibirán datos, porque se perdieron datos.

    – Anton-M

    20 de abril de 2013 a las 21:32

1646968751 16 Como hacer que el servicio de Android se comunique con
señorcopo de nieve

Hay tres formas obvias de comunicarse con los servicios:

  1. Uso de intenciones
  2. Usando AIDL
  3. Usando el propio objeto de servicio (como singleton)

En su caso, elegiría la opción 3. Haga una referencia estática al propio servicio y rellénelo en onCreate():

void onCreate(Intent i) {
  sInstance = this;
}

Hacer una función estática MyService getInstance()que devuelve la estática sInstance.

luego en Activity.onCreate() inicia el servicio, espera de forma asíncrona hasta que el servicio realmente se inicie (puede hacer que su servicio notifique a su aplicación que está lista enviando una intención a la actividad) y obtenga su instancia. Cuando tenga la instancia, registre su objeto de escucha de servicio en su servicio y estará listo. NOTA: al editar Vistas dentro de la Actividad, debe modificarlas en el subproceso de la interfaz de usuario, el servicio probablemente ejecutará su propio Subproceso, por lo que debe llamar Activity.runOnUiThread().

Lo último que debe hacer es eliminar la referencia a su objeto de escucha en Activity.onPause()de lo contrario, se filtrará una instancia de su contexto de actividad, no es bueno.

NOTA: este método solo es útil cuando su aplicación/actividad/tarea es el único proceso que accederá a su servicio. Si este no es el caso, debe usar la opción 1. o 2.

  • Cómo puedo busy-wait ¿la actividad? ¿Puedes explicar por favor?

    – iTurki

    24 de julio de 2011 a las 13:13

  • Entonces, ya sea después de onCreate o después de onStartCommand en su clase de servicio, establezca una variable estática pública, llámela isConnected o algo como verdadero. Luego, en su actividad, haga esto: Intento Intento = nuevo Intento (acto, YourService.class); startService(intención); while(!SuServicio.estáConectado) { sleep(300); } Después de ese ciclo, su servicio se está ejecutando y puede comunicarse con él. En mi experiencia, definitivamente existen algunas limitaciones para interactuar con un servicio como este.

    –Matt Wolfe

    28 de diciembre de 2011 a las 1:10


  • Por qué solo se puede iniciar en Activity.onCreate()?

    – pared del cielo

    29/04/2012 a las 22:50

  • Cualquier palabra sobre por qué no querrías usar Intents enviando datos a través de Parcellable mensajes entre ellos?

    – Aman Alam

    14 de diciembre de 2012 a las 7:09

  • Esto funciona, pero la respuesta de @MaximumGoat es mucho más clara y no implica una espera ocupada.

    – Mateo

    3 de junio de 2013 a las 18:46


1646968752 157 Como hacer que el servicio de Android se comunique con
Jack Gao

Utilizar LocalBroadcastManager para registrar un receptor para escuchar una transmisión enviada desde un servicio local dentro de su aplicación, la referencia va aquí:

http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html

Me sorprende que nadie haya dado referencia a la biblioteca Otto event Bus

http://square.github.io/otto/

He estado usando esto en mis aplicaciones de Android y funciona a la perfección.

1646968752 610 Como hacer que el servicio de Android se comunique con
Kjetil

El uso de Messenger es otra forma sencilla de comunicarse entre un Servicio y una Actividad.

En la Actividad, cree un Controlador con un Mensajero correspondiente. Esto manejará los mensajes de su Servicio.

class ResponseHandler extends Handler {
    @Override public void handleMessage(Message message) {
            Toast.makeText(this, "message from service",
                    Toast.LENGTH_SHORT).show();
    }
}
Messenger messenger = new Messenger(new ResponseHandler());

El Messenger se puede pasar al servicio adjuntándolo a un Mensaje:

Message message = Message.obtain(null, MyService.ADD_RESPONSE_HANDLER);
message.replyTo = messenger;
try {
    myService.send(message);
catch (RemoteException e) {
    e.printStackTrace();
}

Puede encontrar un ejemplo completo en las demostraciones de la API: MessengerService y MessengerServiceActivity. Consulte el ejemplo completo para saber cómo funciona MyService.

  • ¡Muy apreciado! Funciona perfectamente. Solo un detalle en el código: myService.send(message); debiera ser messenger.send(message); en lugar de.

    –Federico Cristina

    3 de agosto de 2019 a las 19:43

Como hacer que el servicio de Android se comunique con
Vlad

También puede usar LiveData que funciona como un EventBus.

class MyService : LifecycleService() {
    companion object {
        val BUS = MutableLiveData<Any>()
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        super.onStartCommand(intent, flags, startId)

        val testItem : Object

        // expose your data
        if (BUS.hasActiveObservers()) {
            BUS.postValue(testItem)
        }

        return START_NOT_STICKY
    }
}

Luego agregue un observador de su Activity.

MyService.BUS.observe(this, Observer {
    it?.let {
        // Do what you need to do here
    }
})

Puedes leer más de esto Blog.

  • ¡Muy apreciado! Funciona perfectamente. Solo un detalle en el código: myService.send(message); debiera ser messenger.send(message); en lugar de.

    –Federico Cristina

    3 de agosto de 2019 a las 19:43

1646968753 46 Como hacer que el servicio de Android se comunique con
miguel

El otro método que no se menciona en los otros comentarios es vincular el servicio desde la actividad usando bindService() y obtener una instancia del servicio en la devolución de llamada de ServiceConnection. Como se describe aquí http://developer.android.com/guide/components/bound-services.html

  • Esta es la forma correcta de obtener la referencia de la instancia de servicio.

    – 김준호

    21 de mayo de 2016 a las 10:13

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad