Cómo hacer que el servicio Android se comunique con la actividad
Estoy escribiendo mi primera aplicación de Android y tratando de obtener mi cabeza en torno a la comunicación entre los servicios y las actividades. Tengo un servicio que se ejecutará en segundo plano y hacer algunos gps y tiempo basado en el registro. Tendré una Actividad que se utilizará para iniciar y detener el Servicio.
Así que primero, tengo que ser capaz de averiguar si el servicio se está ejecutando cuando se inicia la actividad. Hay algunas otras preguntas aquí acerca de eso, así que creo que puedo entender eso (pero no dude en ofrecer consejo).
- Cómo detectar el botón de volumen haga clic en el servicio de fondo o en el entorno nativo en Android?
- Retraso en el lanzamiento de la actividad del servicio de chat principal
- ¿Qué hace setAction () para intención (Broadcast)
- Android - Uso de Google Analytics v4 Campaign Measurement
- Google Analytics V4 Medición de la campaña Las pruebas no funcionan
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. Cuerdas simples y números enteros en este punto – mensajes de estado en su mayoría. Los mensajes no suceden con regularidad, así que no creo que el servicio de sondeo sea un buen camino si hay otra forma. Sólo quiero esta comunicación cuando la Actividad ha sido iniciada por el usuario – No quiero iniciar la Actividad del 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 actividad cuando sucede algo interesante. Si no inicia la Actividad, no verá estos mensajes (no son tan interesantes).
Parece que debería ser capaz de determinar si el servicio se está ejecutando, y si es así, agregar la actividad como un oyente. A continuación, elimine la actividad como un oyente cuando la actividad se detiene o se detiene. ¿Es realmente posible? La única manera que puedo imaginar para hacerlo es tener el implemento de la actividad parcelable y construir un archivo de AIDL así que puedo pasarlo a través de la interfaz alejada del servicio. Eso parece como exceso, sin embargo, y no tengo ni idea de cómo la actividad debe 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 código de ejemplo de Google para manejar esto a través de AIDL en el directorio de samples: /apis/app/RemoteService.java
- Transmitir datos a onDestroy () de Service
- ¿Cómo comprobar si una actividad se está ejecutando en segundo plano / primer plano de un servicio?
- Simular Android matando y reiniciar el servicio
- StartForeground causando problemas con cordova
- Cómo obtener la intención que detiene el servicio en android
- Servicio y cordova plugin
- Android Start_redeliver_intent tarda mucho tiempo (horas) en reiniciar el servicio
- ¿Cómo hacer que el daemon nativo de Unix / Linux funcione en Android?
Hay tres maneras obvias de comunicarse con los servicios:
- Usando Intenciones
- Uso de AIDL
- Utilizar el objeto de servicio en sí (como singleton)
En su caso, me gustaría ir con la opción 3. Hacer una referencia estática para el servicio de sí mismo y llenarlo en onCreate ():
void onCreate(Intent i) { sInstance = this; }
Hacer una función estática MyService getInstance()
, que devuelve la sInstance
estática.
A continuación, en Activity.onCreate()
inicia el servicio, de forma asíncrona espere hasta que el servicio se inicie realmente (puede hacer que su servicio notifique su aplicación está lista enviando una intención a la actividad) y obtenga su instancia. Cuando tenga la instancia, registre su objeto de escucha de servicio a su servicio y está configurado. NOTA: al editar vistas dentro de la actividad, debe modificarlas en el subproceso de interfaz de usuario, es probable que el servicio ejecute su propio subproceso, por lo que debe llamar a Activity.runOnUiThread()
.
Lo último que debe hacer es quitar la referencia a su objeto de escucha en Activity.onPause()
, de lo contrario una instancia de su contexto de actividad se verá, no es buena.
NOTA: Este método sólo es útil cuando su aplicación / Actividad / tarea es el único proceso que tendrá acceso a su servicio. Si éste no es el caso usted tiene que utilizar la opción 1 o 2.
El asker probablemente desde hace mucho tiempo pasó esto, pero en caso de que alguien más busque esto …
Hay otra manera de manejar esto, que creo que podría ser la más simple.
Agregue un BroadcastReceiver a su actividad. Regístrelo para recibir algún intento personalizado en onResume y anótelo en onPause. A continuación, enviar esa intención de su servicio cuando desea enviar sus actualizaciones de estado o lo que tiene.
Asegúrese de que no sería infeliz si alguna otra aplicación escuchada por su intención (¿alguien podría hacer algo malicioso?), Pero más allá de eso, usted debe estar bien.
Se solicitó una muestra de código:
En mi servicio, tengo:
// Do stuff that alters the content of my local SQLite Database sendBroadcast(new Intent(RefreshTask.REFRESH_DATA_INTENT));
(RefreshTask.REFRESH_DATA_INTENT es sólo 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;
Anular onResume para agregar:
if (dataUpdateReceiver == null) dataUpdateReceiver = new DataUpdateReceiver(); IntentFilter intentFilter = new IntentFilter(RefreshTask.REFRESH_DATA_INTENT); registerReceiver(dataUpdateReceiver, intentFilter);
Y anularé onPause para agregar:
if (dataUpdateReceiver != null) unregisterReceiver(dataUpdateReceiver);
Ahora mi actividad está escuchando mi servicio para decir "Hey, vaya a ponerse al día". Podría pasar los datos en el intento en lugar de actualizar las tablas de la base de datos y luego volver a buscar 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.
Utilice LocalBroadcastManager
para registrar un receptor para escuchar una emisión enviada desde localservice dentro de su aplicación, la referencia va aquí:
http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html
El uso de un Messenger es otra forma sencilla de comunicarse entre un Servicio y una Actividad.
En la actividad, cree un controlador con un Messenger 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(); }
Un ejemplo completo se puede encontrar en las demos API: MessengerService y MessengerServiceActivity . Consulte el ejemplo completo de cómo funciona MyService.
Me sorprende que nadie haya dado referencia a Otto evento Bus biblioteca
He estado usando esto en mis aplicaciones Android y funciona sin problemas.
El otro método que no se menciona en los otros comentarios es vincular al servicio de la actividad que utiliza bindService () y obtener una instancia del servicio en la devolución de llamada ServiceConnection. Como se describe aquí http://developer.android.com/guide/components/bound-services.html
Otra manera podría ser el uso de observadores con una clase de modelo falso a través de la actividad y el servicio en sí, la aplicación de una variación de patrón MVC. No sé si es la mejor manera de lograr esto, pero es la forma en que funcionó para mí. Si usted necesita algún ejemplo pida él y fijaré algo.
Para hacer un seguimiento de @MrSnowflake respuesta con un ejemplo de código. Esta es la clase de Application
código abierto XABBER ahora . La clase Application
está centralizando y coordinando Listeners
y ManagerInterfaces y más. Los gestores de todo tipo se cargan dinámicamente. Activity´s
iniciada en el Xabber informará en qué tipo de Listener
son. Y cuando un Service
inicia informe en la clase de la Application
como comenzada. Ahora para enviar un mensaje a una Activity
todo lo que tienes que hacer es hacer que tu Activity
convierta en un listener
de qué tipo necesitas. En OnStart()
OnPause()
register / unreg. El Service
puede solicitar a la clase de la Application
sólo para ese listener
que necesita hablar y si está allí entonces la Actividad está lista para recibir.
Pasando por la clase de Application
verá que hay un botín más en marcha, entonces esto.