2010-03-18 18 views
37

Estoy tratando de crear una aplicación Android simple que tenga una ActivityList de información, cuando la aplicación comience, planeo iniciar un servicio que estará constantemente calculando los datos (va a cambiar) y quiero que ActivityList esté sincronizado con los datos que el servicio está calculando durante la vida útil de la aplicación.¿Cómo puedo actualizar la información en una actividad de Android desde un fondo? Servicio

¿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 de antemano

Respuesta

91

¿Cómo puedo configurar mi actividad para que sea escuchando el Servicio? ¿Es esta la la mejor manera de abordar este problema?

tiene tres opciones principales, tal como lo veo:

  1. sondeo. El 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, el Activity registra un objeto de devolución de llamada ("observador") con el Service. El Service invoca un método en la devolución de llamada cuando los datos cambian, lo que a su vez actualiza la interfaz de usuario. Puede ver un ejemplo de cómo usar eso con un Servicehere.

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

+11

Gran ejemplo del número 3 aquí ... http://www.websmithing.com/2011/02/01/how-to-update-the-ui-in-an-android-activity-using-data-from- a-background-service/ –

+1

¿Qué sucede si cerré la aplicación? ¿Cómo puedo manejar el caso de ejecutar AlarmManager con actividad de estado? – Basbous

+2

¿Cuáles son los pro y los contras de las técnicas 2 y 3? –

4

Este sonido 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 sabe nada sobre Design Patterns compre "Head First Design Patterns", es fácil de leer y está lleno de buena información.

PD: Lo estoy leyendo ahora.

+8

Tiene razón, pero esta respuesta no es de ninguna manera específica de Android ... – Janusz

0

Se ejecutará un hilo de fondo 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 vista de lista que debe actualizarse en la siguiente posibilidad.

+2

Mejor aún, si va a utilizar 'ArrayAdapter', simplemente llame a' add() ',' insert() ', y' remove() 'métodos en' ArrayAdapter' para cambiar su contenido. No necesita 'notifyDataSetChanged()' luego. – CommonsWare

0

Debe vincular 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); 
    } 
} 
+0

Esto no es exactamente lo que solicitó OP. Si bien esto podría funcionar (el Servicio actualiza continuamente los datos y la IU puede solicitar los nuevos datos), requiere una llamada del lado de la IU como reacción a la entrada del usuario (como presionar un botón). La pregunta, por el contrario, pide una forma de que la UI se actualice continuamente con los nuevos datos en el Servicio. –

0

Estoy muy, muy preguntándose por qué nadie menciona un enfoque simple utilizando un EventBus por cualquier biblioteca. Esto es por supuesto si no estás usando RX. Mi favorito personal es EventBus por 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.

Cuestiones relacionadas