2010-03-18 9 views
37

Sto provando a creare una semplice applicazione Android con una ActivityList di informazioni, quando l'applicazione si avvia, ho intenzione di avviare un servizio che calcolerà costantemente i dati (cambierà) e voglio che ActivityList sia sincronizzato con i dati che il servizio sta calcolando per la vita dell'app.Come aggiornare le informazioni in un'attività Android da un servizio in background

Come posso impostare la mia attività per ascoltare il servizio? È questo il modo migliore per affrontare questo problema?

Ad esempio, se si immagina un elenco di quotazioni azionarie, i dati verrebbero modificati regolarmente e devono essere sincronizzati con il servizio (nel mio caso) che calcola/recupera costantemente i dati.

Grazie in anticipo

risposta

91

Come impostare la mia attività su ascoltando il servizio? È questo il modo migliore per affrontare questo problema con il ?

avete tre opzioni principali, come la vedo io:

  1. Polling. Il Activity richiede periodicamente lo Service per i dati più recenti. IMHO, questa opzione fa schifo, ma è certamente possibile.

  2. Richiamate. Per risposta di jax, lo Activity registra un oggetto di richiamata ("observer") con lo Service. Il Service richiama un metodo sul callback quando i dati cambiano, che a sua volta aggiorna l'interfaccia utente. Puoi vedere un esempio di utilizzo di questo con Servicehere.

  3. Trasmissione Intents. Il Service trasmette un Intent tramite sendBroadcast() in caso di modifica dei dati. Il Activity registra un BroadcastReceiver utilizzando registerReceiver() e quello BroadcastReceiver viene notificato di una trasmissione in arrivo. Ciò innesca lo Activity per caricare gli ultimi dati dallo Service o, eventualmente, solo per ottenere gli ultimi dati dagli extra nella trasmissione Intent.Puoi vedere un esempio dell'uso di quella tecnica con un Servicehere.

+11

Grande esempio del numero 3 qui ... http://www.websmithing.com/2011/02/01/how-to-update-the-ui-in-an-android-activity-using-data-from- a-background-service/ –

+1

Cosa succede se ho chiuso l'applicazione. Come posso gestire il caso di esecuzione di AlarmManager con Status Activity. – Basbous

+2

Quali sono i pro ei contro delle tecniche 2 e 3? –

4

Suona come un buon candidato per il modello di osservatore. Fondamentalmente la tua attività (The Observer) si registrerà con il servizio in background (The Observable) e potrai spingere o tirare dati dalla tua attività. Il tuo osservatore in questo caso sarà la tua attività e l'osservabile sarà il tuo servizio.

Se non si sa nulla di Design Patterns acquistare "Head First Design Patterns", è facile da leggere ed è pieno di grandi informazioni.

PS: Lo sto leggendo ora.

+8

Hai ragione ma questa risposta non è in alcun modo specifica per Android ... – Janusz

0

È in esecuzione un thread in background che calcola le modifiche nell'elenco. Questa discussione ora ha la possibilità di notificare alla GUI che l'elenco è stato aggiornato.

È possibile utilizzare una sorta di ArrayAdapter per ottenere i dati in ListView. L'ArrayAdapter ha un metodo chiamato adpater.notifyDataSetChanged() ogni volta che si chiama questo metodo, l'adattatore vedrà che i dati corrispondenti sono cambiati e quindi notificherà al listview che dovrebbe aggiornarsi alla prossima possibilità.

+2

Meglio ancora, se hai intenzione di usare 'ArrayAdapter', chiama semplicemente' add() ',' insert() ', e' rimuovi() 'metodi su' ArrayAdapter' per cambiarne il contenuto. Non hai bisogno di 'notifyDataSetChanged()' allora. – CommonsWare

0

È necessario utilizzare bindService() per associare l'attività al servizio in esecuzione e comunicare con esso.

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; 
    } 
}; 
} 

e il vostro servizio come:

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

Questo non è esattamente ciò che l'OP chiedeva. Mentre questo potrebbe funzionare (il servizio aggiorna continuamente i dati e l'interfaccia utente può chiedere i nuovi dati), richiede una chiamata dal lato dell'interfaccia utente come reazione all'input dell'utente (come una pressione di un pulsante). La domanda, al contrario, richiede un modo per l'interfaccia utente di aggiornare continuamente con i nuovi dati nel servizio. –

0

Sono davvero, davvero chiedendosi perché nessuno ha menzionato un approccio semplice utilizzando un EventBus con qualsiasi libreria. Questo è ovviamente se non stai usando RX. Il mio preferito è EventBus di GreenRobot. https://github.com/greenrobot/EventBus

Con solo un paio di linee di codice e nessuna interfaccia. Spara un evento e ascoltalo ovunque tu voglia. È disaccoppiato, è thread-safe e non bloccherà la tua app.

Problemi correlati