J'essaie de créer une application Android simple comportant une liste d'activités, lorsque celle-ci démarre, je prévois de démarrer un service qui calculera constamment les données (elles changeront) et je veux que la liste d'activités soit synchronisée avec les données que le service calcule pour la vie de l'application.
Comment puis-je configurer mon activité pour être à l'écoute du service? Est-ce la meilleure façon d'aborder ce problème?
Par exemple, si vous imaginez une liste de cours boursiers, les données seraient modifiées régulièrement et doivent être synchronisées avec le service (dans mon cas) qui calcule/récupère les données en permanence.
Merci d'avance
Comment puis-je configurer mon activité pour être écouter le service? Est-ce le meilleure façon d'aborder ce problème?
Vous avez trois options principales, comme je le vois:
Vote. La Activity
demande périodiquement à la Service
les dernières données. IMHO, cette option est nulle, mais c'est certainement possible.
Rappels. Selon la réponse de jax, la variable Activity
enregistre un objet de rappel ("observateur") avec la variable Service
. La Service
appelle une méthode sur le rappel lorsque les données sont modifiées, ce qui met à jour l'interface utilisateur. Vous pouvez voir un exemple d'utilisation de cela avec une variable Service
here .
Broadcast Intents
. La Service
diffuse une Intent
via sendBroadcast()
sur un changement de données. La Activity
enregistre une BroadcastReceiver
en utilisant registerReceiver()
, et cette BroadcastReceiver
est avertie d'une diffusion entrante. Ceci déclenche la Activity
pour charger les dernières données de la Service
, ou éventuellement simplement pour extraire les dernières données des extras de la diffusion Intent
. Vous pouvez voir un exemple d'utilisation de cette technique avec un Service
ici .
Cela semble être un bon candidat pour le modèle Observer. Fondamentalement, votre activité (The Observer) s’enregistrera elle-même auprès du service d’arrière-plan (The Observable) et vous pourrez alors pousser ou extraire des données de votre activité. Dans ce cas, votre observateur sera votre activité et l'observable sera votre service.
Si vous ne connaissez rien aux modèles de conception, achetez "Head First Design Patterns", il est facile à lire et regorge d'informations de qualité.
PS: Je le lis maintenant.
Je me demande vraiment pourquoi personne ne mentionne une approche simple utilisant un EventBus de quelque bibliothèque que ce soit. Ceci est bien sûr si vous n'utilisez pas RX. Mon préféré est EventBus de GreenRobot . https://github.com/greenrobot/EventBus
Avec seulement quelques lignes de code et aucune interface. Organisez un événement et écoutez-le où vous voulez. Il est découplé, il est thread-safe et il ne fera pas planter votre application.
Vous aurez un thread en arrière-plan en cours d'exécution qui calcule les modifications dans la liste. Ce fil doit maintenant avoir la 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 ListView. ArrayAdapter a une méthode appelée adpater.notifyDataSetChanged () chaque fois que vous appelez cette méthode, l'adaptateur verra que les données correspondantes ont été modifiées, puis notifiera au listview qu'il doit être mis à jour à la prochaine occasion.
Vous devez utiliser bindService () pour lier l'activité au service en cours d'exécution et 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);
}
}