Comment puis-je mettre à jour l'information dans une activité Android d'un service d'arrière-plan
-
20-09-2019 - |
Question
Je suis en train de créer une simple application Android qui a une ActivityList d'information, lorsque l'application démarre, je prévois de lancer un service qui sera calcule en permanence les données (il va changer) et je veux que le ActivityList être en synchronisation avec les données que le service est le calcul de la durée de vie de l'application.
Comment puis-je configurer mon activité à l'écoute du service? Est-ce la meilleure façon d'aborder ce problème?
Par exemple, si vous imaginez une liste des cours boursiers -. Les données seraient être changés régulièrement et doivent être en phase avec le (dans mon cas) de service qui calculait / récupérer les données en permanence
Merci d'avance
La solution
Comment puis-je configurer mon activité à l'écoute du service? Est-ce le meilleure façon d'aborder ce problème?
Vous disposez de trois grandes options, comme je le vois:
-
Polling. Le
Activity
demande périodiquement à laService
pour les données les plus récentes. À mon humble avis, cette option est nul, mais il est certainement possible. -
Callbacks. Par la réponse de Jax, le
Activity
enregistre un objet de rappel ( « observateur ») avec leService
. LaService
invoque une méthode sur la fonction de rappel lorsque les changements de données, ce qui met à jour l'interface utilisateur. Vous pouvez voir un exemple d'utilisation que d'unService
. -
Diffusion
Intents
. LaService
diffuse uneIntent
viasendBroadcast()
sur un changement de données. LeActivity
enregistre unBroadcastReceiver
en utilisantregisterReceiver()
, et queBroadcastReceiver
est informé d'une émission entrante. Cela déclenche laActivity
pour charger les données les plus récentes de laService
, ou peut-être juste pour obtenir les données les plus récentes sur extras dans laIntent
de diffusion. Vous pouvez voir un exemple d'utilisation de cette technique avec unService
.
Autres conseils
Ce son comme un bon candidat pour le motif d'observateur. Fondamentalement, votre activité (The Observer) s'inscrira avec le service d'arrière-plan (Le Observable) et vous pouvez pousser ou tirer des données de votre activité. Votre observateur dans ce cas sera votre activité et la Observable sera votre service.
Si vous ne savez rien sur les modèles de conception BUY "Head First Design Patterns", il est facile à lire et est plein de grande information.
PS. Je lis maintenant
Je suis vraiment, vraiment se demander pourquoi personne n'a mentionné une approche simple en utilisant un EventBus par quelque bibliothèque. Ceci est bien sûr si vous ne l'utilisez RX. Mon préféré est EventBus par GreenRobot. https://github.com/greenrobot/EventBus
Avec seulement quelques lignes de code, et aucune interface. Feu d'un événement, et écouter où vous voulez. Il est découplé, il est thread-safe, et il ne plantera pas votre application.
Vous devez utiliser bindService () pour lier l'activité avec un service en cours d'exécution et de communiquer avec elle.
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;
}
};
}
et votre service comme:
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);
}
}
Vous aurez une course de fil d'arrière-plan qui calcule les changements dans la liste. Ce fil a besoin maintenant une possibilité d'informer l'interface graphique que la liste a été mise à jour.
Vous pouvez utiliser une sorte de ArrayAdapter pour obtenir les données dans le ListView. Le ArrayAdapter a une méthode appelée adpater. notifyDataSetChanged () chaque fois que vous appelez cette méthode, l'adaptateur voir que les données correspondantes ont changé et informer le listview qu'il doit mettre à jour la possibilité suivante.