¿Cuál es la forma preferida de volver a llamar a una actividad de Android desde un subproceso de servicio

Actualmente estoy desarrollando una aplicación de Android que tiene las siguientes necesidades:

Se inició un subproceso de trabajo en un servicio. Este subproceso hace algún procesamiento y debe invocarse desde la Actividad principal y proporcionar algunas respuestas asíncronas a la misma Actividad.

Invocar el servicio de la actividad es fácil (IBinder cosas)

Mi pregunta ahora es sobre la correcta implementación de la devolución de llamada del servicio.

Primero iba a agregar un android.os.Handler en la actividad y manejar las respuestas del hilo en MyActivity.handleMessage (Message), pero esto requiere que yo dé la referencia de este manejador al servicio. Entonces, ¿qué sucede cuando el sistema operativo Android decide destruir / recrear mi actividad debido a un cambio de orientación, por ejemplo? ¿Mi actividad se mantiene viva como se hace referencia (indirectamente) en el servicio? Si la Actividad se destruyó / reconstruyó de todos modos, ¿qué sucede con mi referencia del Manejador en el Servicio?

Supongo que no estoy utilizando el método correcto para llamar una actividad de un hilo de servicio, así que quería saber si alguien puede señalarme la forma correcta de hacerlo.

TIA

Prefiero usar LocalBroadcastManager

He aquí un ejemplo del código en su Activity :

 BroadcastReceiver localBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.d("BroadcastReceiver", "Message received " + intent.getAction()); Log.d("BroadcaseReceiver", "Received data " + intent.getStringExtra("com.my.package.intent.EXTRA_DATA")); } }; @Override protected void onStart() { super.onStart(); final LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this); final IntentFilter localFilter = new IntentFilter(); localFilter.addAction("com.my.package.intent.ACTION_NAME_HERE"); localBroadcastManager.registerReceiver(localBroadcastReceiver, localFilter); } @Override protected void onStop() { super.onStop(); final LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this); // Make sure to unregister!! localBroadcastManager.unregisterReceiver(localBroadcastReceiver); } 

En cualquier otro lugar de su base de código (como en la finalización de su subproceso de fondo):

 final LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context); final Intent intent = new Intent("com.my.package.intent.ACTION_NAME_HERE") intent.putExtra("com.my.package.intent.EXTRA_DATA", yourBackgroundData); localBroadcastManager.sendBroadcast(intent); 

Por supuesto, puede utilizar la intent.putExtra de intent.putExtra para agregar datos adicionales o utilizar varias acciones para diferenciar los mensajes de difusión.

Hemos hecho esto centralizando toda la comunicación entre las actividades y el servicio en la clase de Application . Extendemos la clase Application y luego tenemos métodos allí que se enlazan al servicio y aceptan las devoluciones de llamada. No existe una conexión directa entre una Activity y el Service en esta arquitectura.

La ventaja de este mecanismo es que usted no tiene que preocuparse de unbinding / rebinding al servicio durante las transiciones de la actividad y la muerte de la actividad y las reconstrucciones. La clase de Application gestiona todo esto y no se ve afectada por lo que hacen las actividades. La clase Application recibe todas las devoluciones de llamada y necesitará tener código allí para determinar qué hacer con las devoluciones de llamada. Es probable que desee almacenar algunos datos en la clase Application y, a continuación, notificar a las actividades que hay nuevos datos disponibles, o algo similar.

Otro enfoque es hacer que el Service retransmita las devoluciones de llamada. En este caso, el acoplamiento entre el servicio y las actividades está suelto, por lo que no es necesario crear un Handler en la actividad y luego pasarlo al Service . Las actividades sólo pueden registrar BroadcastReceiver s para las devoluciones de llamada en las que están interesados, o puede administrar esto en el manifiesto.

Una solución, como usted dice, es usar MyActivity.handleMessage (Message). Siempre que su actividad se inicie (o se reinicie) probablemente intentará iniciar el servicio (el "onBind" cosas que usted menciona). Si el servicio ya se está ejecutando, no se produce ningún daño. Una vez que se ha completado el enlace, indica al servicio al que el Messenger envía respuestas.

Para asegurarse de que se reinician los reinicios, en onStop necesitas decirle al servicio que elimine ese Messenger de su "lista de lugares para enviar respuestas" para que no envíe accidentalmente un mensaje a un Messenger que ahora no existe. Cuando onStart se llama como parte del reinicio, enviará el Messenger ahora correcto.

Obviamente, esto requiere que el servicio manejar esto y de alguna manera gestionar el escenario en el que tiene una respuesta a enviar, mientras que no hay Messenger para enviarlo a. Ya sea que contenga información hasta que el Messenger esté disponible o que descarte la información, y la Actividad obtiene toda la información de estado explícitamente como un seguimiento a las cosas de enlace que ha hecho en onStart.

Otra aproximación es hacer que la actividad encueste el Servicio cada cierto tiempo (10 segundos?) Cuando se sabe que hay procesamiento para ver si los resultados están disponibles, y luego para dejar de sondear una vez que toda la información está de vuelta.

Para las llamadas de servicio asíncronas, uno pasaría una referencia de devolución de llamada al iniciarla, diría yo.

La devolución de llamada se va a ejecutar por el subproceso de enlace, que es estándar para este enfoque.

Por supuesto, la Actividad que inicia la llamada puede basarse en el hecho de que el hilo de unión funciona en su propio proceso. Así que es bastante fácil volver al principal / UI hilo de la devolución de llamada.

Por lo tanto, si la devolución de llamada necesita procesar algo en el subproceso main / UI, sólo utiliza

 (new Handler(Looper.getMainLooper()).post() 

Que tiene la ventaja de que encuentra el hilo principal / UI dinámicamente en el momento en que se ejecuta el código. Por otro lado, eso ni siquiera es necesario porque el subproceso principal / UI no cambia, por lo que encontrarlo a través de una referencia View o cualquier otra cosa que pueda tener a mano en la devolución de llamada también funcionaría.

  • Cómo pasar en dos tipos de datos diferentes a AsyncTask, Android
  • ¿Es el hilo de ArrayAdapter seguro en android? Si no, ¿qué puedo hacer para que sea seguro?
  • Controlador de Android para activar el hilo
  • No se puede crear un WebView en un subproceso
  • Cómo administrar el número de subprocesos dentro de la tarea de sincronización
  • Android: ¿Cuál es la forma más suave de sincronizar una base de datos remota en segundo plano?
  • Android - Prevenga la pantalla blanca al inicio
  • Handler.sendMessageDelayed (msg, delay) no funciona correctamente
  • Equivalente a javax.swing.Timer en Android
  • Facebook y GoogleAnalytics está causando la señal fatal 11 (SIGSEGV)
  • Es la biblioteca Java.util.concurrent mejor al hacer cualquier tipo de tarea sobre el estándar Android AsyncTask
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.