¿Cómo puedo actualizar la información en una actividad de Android desde un servicio en segundo plano?

Intento crear una aplicación de Android simple que tenga una ActivityList de información, cuando se inicie la aplicación, planeo iniciar un servicio que estará constantemente calculando los datos (se cambiará) y quiero que ActivityList esté sincronizado con los datos que el servicio está calculando durante la vida de la aplicación.

¿Cómo puedo configurar mi actividad para escuchar el servicio? ¿Es esta la mejor manera de abordar este problema?

Por ejemplo, si imagina una lista de precios de acciones, los datos se cambiarán regularmente y deben estar sincronizados con el servicio (en mi caso) que está calculando / obteniendo los datos constantemente.

Gracias por adelantado

¿Cómo puedo configurar mi actividad para escuchar el servicio? ¿Es esta la mejor manera de abordar este problema?

Tienes tres opciones principales, como yo lo veo:

  1. Votación. La Activity solicita periódicamente al Service los últimos datos. En mi humilde opinión, esta opción apesta, pero ciertamente es posible.

  2. Devolución de llamada Por respuesta de jax, la Activity registra un objeto de callback (“observador”) con el Service . El Service invoca un método en la callback cuando los datos cambian, lo que a su vez actualiza la UI. Puede ver un ejemplo de cómo usar eso con un Service aquí .

  3. Intents transmisión. El Service difunde un Intent través de sendBroadcast() en un cambio de datos. La Activity registra un BroadcastReceiver utilizando registerReceiver() , y se le notifica a BroadcastReceiver de una emisión entrante. Esto activa la Activity para cargar los datos más recientes del Service , o posiblemente solo para obtener los últimos datos de los extras en el Intent transmisión. Puede ver un ejemplo del uso de esa técnica con un Service aquí .

Esto suena como un buen candidato para el patrón de observador. Básicamente, su actividad (The Observer) se registrará con el servicio en segundo plano (The Observable) y podrá enviar o extraer datos de su actividad. Su Observador en este caso será su Actividad y el Observable será su Servicio.

Si no sabes nada sobre patrones de diseño, compra “Patrones de diseño de Head First”, es fácil de leer y está lleno de buena información.

PD: Lo estoy leyendo ahora.

Tendrá un hilo de fondo en ejecución que calcula los cambios en la lista. Este hilo ahora necesita la posibilidad de notificar a la GUI que la lista se actualizó.

Puede usar algún tipo de ArrayAdapter para obtener los datos en ListView. El ArrayAdapter tiene un método llamado adpater.notifyDataSetChanged () cada vez que llame a este método, el adaptador verá que los datos correspondientes han cambiado y luego notificará a la lista que se debe actualizar en la siguiente posibilidad.

Debe usar bindService () para vincular la actividad con el servicio en ejecución y comunicarse con él.

 public class BindingActivity extends Activity { YourService mService; boolean mBound = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to Your Service Intent intent = new Intent(this, YourService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // Unbind from the service if (mBound) { unbindService(mConnection); mBound = false; } } /** Called when a button is clicked (the button in the layout file attaches to * this method with the android:onClick attribute) */ public void onButtonClick(View v) { if (mBound) { // Call a method from your Service. // However, if this call were something that might hang, then this request should // occur in a separate thread to avoid slowing down the activity performance. int num = mService.getRandomNumber(); Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); } } /** Defines callbacks for service binding, passed to bindService() */ private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to the running Service, cast the IBinder and get instance LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName arg0) { mBound = false; } }; } 

y su servicio como:

 public class LocalService extends Service { // Binder given to clients private final IBinder mBinder = new LocalBinder(); // Random number generator private final Random mGenerator = new Random(); /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder { LocalService getService() { // Return this instance of LocalService so clients can call public methods return LocalService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } /** method for clients */ public int getRandomNumber() { return mGenerator.nextInt(100); } } 

Realmente, me estoy preguntando por qué nadie mencionó un enfoque simple usando un EventBus en cualquier biblioteca. Esto es por supuesto si no estás usando RX. Mi favorito personal es EventBus de GreenRobot. https://github.com/greenrobot/EventBus

Con solo un par de líneas de código y sin interfaces. Dispara un evento y escúchalo donde quieras. Está desacoplado, es seguro para subprocesos y no bloqueará su aplicación.