Você está na página 1de 12

Utiliser les services sous Android - Android - Le blog d'un dveloppeur http://blog.developpez.

com/android23/p8571/android/creation-de-service/

Forums Tutoriels Magazine FAQs Blogs Projets Chat Newsletter tudes Emploi Club Contacts

Accueil Conception Java .NET Dv. Web EDI Langages SGBD Office Solutions d'entreprise Applications Systmes

INDEX DES BLOGS REGLES ENREGISTREZ-VOUS IDENTIFIEZ-VOUS OUVREZ VOTRE BLOG

Blogs des dveloppeurs Android - Le blog d'un dveloppeur

Article complet: Utiliser les services sous Android


26/02/2010

14:54:06, Catgories: Rcapitulatif Java, Android, Android, 6754 mots , Nicolas Druet

[Android][Java] Utiliser les services sous Android

A l'instar des Activities, des Intents, les services font partie des briques essentielles d'Android. Ils ne disposent pas d'interface utilisateur
mais fonctionnent en arrire plan pour une priode de temps indfinie. L'exemple le plus courant est le lecteur de musique, qui vous
permet d'couter vos mp3 sans bloquer la navigation sur internet ou consultre la liste des vos contacts. Un service peut galement
rapatrier des donnes sur internet tels que des flux RSS.

Dans ce long article nous aborderons :

Les services (threads, cycle de vie...)


Services Locaux (LocalService)
Dclaration du service
Implmentation des listeners
Implmentation d'un binder
Services Distants (RemoteService)
Dclaration du service
Mise en place des Callbacks
Dmarrer le service au boot du tlphone
Exemple : Connexion au service MP3

[Suite:]

> Les services (threads, cycle de vie...)

Les services ont pour but de raliser des tches de fond sans aucune interaction avec l'utilisateur pour une dure indfinie. Il existe deux
type de services :

les services locaux (ou LocalService) qui s'excutent dans le mme processus que votre application
Les services distants (ou RemoteService) qui s'excutent dans un processus diffrent de celui de application

Les services s'excutent dans le Thread principal du processus parent. Ils doivent tre dclars dans le fichier AndroidManifest.xml:
<service android:name=".subpackagename.ServiceName"/>

Ils doivent tendre la classe Service dont vous devrez surcharger les mthodes suivantes en fonction de vos besoins :

void onCreate(); // initialisation des ressources


void onStart(Intent intent); // SDK<2.0 la tche de fond dmarre
void onStartCommand(Intent intent, int flags, int startId); // SDK>2.0 la tche de fond dmarre
void onDestroy(); // libration des ressources

IBinder onBind(Intent intent); // connexion client distant


boolean onUnbind(Intent intent); // dconnexion d'un client
void onRebind(Intent intent)

Google a publi un post sur la mthode onStartCommand() apparue avec le SDK 2.0 :
http://android-developers.blogspot.com/2010/02/service-api-changes-starting-with.html

La mthode onStart() est dprcie mais doit tre redfinie pour une compatibilit avec les SDK antrieurs (si ncessaire).

Quant au cycle de vie d'un service, Google l'illustre de la manire suivante :

Pour interagir (demarrer/arrter...) avec un service, deux possibilits s'offrent nous :

Soit on appelle la mthode startService() qui invoque la mthode onCreate() puis onStart()
service.startService() | -> onCreate() - > onStartCommand() [service running]
L'appel de la mthode stopService() invoque la mthode onDestroy()

Soit on appelle la mthode bindService() qui appelle uniquement la mthode onCreate()


activity.bindService() | ->onCreate() [service created]

Il est possible de voir la liste des services excuts en allant dans Menu > Settings > Applications > Running Services > du tlphone:

1 sur 12 06/04/2011 19:11


Utiliser les services sous Android - Android - Le blog d'un dveloppeur http://blog.developpez.com/android23/p8571/android/creation-de-service/

> Services locaux (LocalService)

>> Dclaration du service

Un service Local n'est accessible que par les Activity de l'application.

Pour l'exemple, notre service initialise un Timer et une tche qui sera excute toutes les minutes. Nous allons crer une classe hritant
de Service et surcharger les mthodes onCreate(), onStart() et onDestroy().

public class BackgroundService extends Service {

private Timer timer ;

@Override
protected void onCreate() {
super.onCreate();
timer = new Timer();
Log.d(this.getClass().getName(), "onCreate");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(this.getClass().getName(), "onStart");
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
// Executer de votre tche
}
}, 0, 60000);

return START_NOT_STICKY;
}

@Override
public void onDestroy() {
Log.d(this.getClass().getName(), "onDestroy");
this.timer.cancel();
}

Nous dclarons le service dans le fichier AndroidManifest.xml l'intrieur de la balise <application> :

<service android:name=".BackgroundService" />

Pour le dmarrer, nous faisons appel la mthode startService(Intent) de l'Activity prenant en paramtre un Intent. Ce dernier
peut tre initialis de deux manires :

Soit en lui passant explicitement le context de l'application et la class du service.

Intent intent = new Intent(this,BackgroundService.class);


startService(intent);

Soit en dclarant une action dans le fichier AndroidManifest.xml...

<service android:enabled="true" android:name=".BackgroundService">


<intent-filter>
<action android:name=".BackgroundService.ACTION" />
</intent-filter>
</service>

... que nous passons au constructeur de l'intent

Intent intent = new Intent(".BackgroundService.ACTION");


startService(intent);

2 sur 12 06/04/2011 19:11


Utiliser les services sous Android - Android - Le blog d'un dveloppeur http://blog.developpez.com/android23/p8571/android/creation-de-service/

Il est possible de passer des objets complets serialisables en paramtre avec les mthodes intent.putExtra(...). Les objets pourront tre
rcuprer dans la mthode onStart(Intent intent, int startId) du service avec intent.getExtras().get(String key). Le
fonctionnement est similaire une table de Hash.

Pour arrter notre service :

Intent intent = new Intent(this,BackgroundService.class);


stopService(intent);

>> Implmentation des listeners

Dans un premier temps, nous allons implmenter un systme de listeners trs simple. L'interface IBackgroundServiceListener
implmente par notre Activity pour couter les mises jour du service est la suivante :

public interface IBackgroundServiceListener {


public void dataChanged(Object o);
}

Nous crons l'interface IBackgroundService :

public interface IBackgroundService {


public void addListener(IBackgroundServiceListener listener);
public void removeListener(IBackgroundServiceListener listener);
}

Nous implmentons l'interface dans le service :

private List<IBackgroundServiceListener> listeners = null;

// Ajout d'un listener


public void addListener(IBackgroundServiceListener listener) {
if(listeners == null){
listeners = new ArrayList<IGoogleWeatherListener>();
}
listeners.add(listener);
}

// Suppression d'un listener


public void removeListener(IBackgroundServiceListener listener) {
if(listeners != null){
listeners.remove(listener);
}
}

// Notification des listeners


private void fireDataChanged(Object data){
if(listeners != null){
for(IBackgroundServiceListener listener: listeners){
listener.dataChanged(data);
}
}
}

Pour accder au service depuis l'Activity nous rajoutons une variable static IBackgroundService service que nous initialiserons dans la
mthode onCreate() :

public class BackgroundService extends Service implements IBackgroundService {


...

private static IBackgroundService service;

@Override
public void onCreate() {
...
service = this;
}

public static IBackgroundService getService() {


return service;
}

...
}

L'emploi d'une variable static n'est pas la meilleure solution. Nous verrons plus tard comment nous en passer. Mais ce stade, il n'est
pas possible d'accder aux mthodes du service et d'appeler un setter.

Nous poursuivons en dfinissant notre listener dans notre Activity:

Intent intent = new


// Lancement du service
Intent(this,BackgroundService.class);
startService(intent);

// Ajout de l'activity la liste des listeners du service


BackgroundService.getService().addListener(new IBackgroundServiceListener() {
public void dataChanged(Object o) {
// mise jour de l'interface graphique
}
});

Au moment voulu, dans la mthode run() du Timer nous ferons appel la mthode prive fireDataChanged(data) pour notifier les
listeners (dans notre cas, l'Activity) de la mise jour des donnes.

Attention ! Si nous nous contentons d'implmenter la mthode dataChanged(), l'exception suivante sera leve au runtime :

3 sur 12 06/04/2011 19:11


Utiliser les services sous Android - Android - Le blog d'un dveloppeur http://blog.developpez.com/android23/p8571/android/creation-de-service/

android.view.ViewRoot$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can touch its views.

En effet, la mthode du listener dataChanged() est appele par le Timer, et donc excute dans le Thread de celui-ci. L'exception nous
indique que toute mise jour de l'interface utilisateur ne peut se faire que par le Thread responsable de la cration des View, Button,
TextView... Nous utilisons donc la mthode runOnUiThread de la classe Activity pour poster des instructions dans l'UiThread :

// Ajout de l'activity la liste des listeners du service


BackgroundService.getService().addListener(new IBackgroundServiceListener() {
public void dataChanged(final Object o) {
MyActivity.this.runOnUiThread(new Runnable() {
public void run() {
// Mise jour de l'UI
}
});
}});

Il nous reste mettre jour la mthode onDestroy() du service pour vider la liste des listeners :

@Override
public void onDestroy() {
this.listeners.clear();
this.timer.cancel();
Log.d(this.getClass().getName(), "onDestroy");
}

A ce stade, nous avons vu comment dclarer notre service et y accder, dfinir une tche de fond, et mettre jour notre interface
utilisateur. Le dfaut de la solution propose est l'utilisation d'une variable static pour accder au service depuis l'Activity.
Malheureusement, la mthode startService(Intent) n'offre pas d'accs direct aux mthodes du services. Pour se faire, nous allons
avoir recours au binding.

>> Implmentation d'un binder

Comme avec un RemoteService, nous allons nous connecter au service et rcuprer un Binder. A travers cet objet nous accderons aux
mthodes public du service via l'interface IBackgroundService que nous avons dfinie plus haut. L'avantage de cette solution est
d'unifier l'utilisation des LocalService et RemoteService mais surtout de rcuprer l'instance du service.

Nous redfinissons la mthode onBind(), modifions l'implmentation du listener et dportons notre tche de fond dans la mthode
_onStart() :

public class BackgroundService extends Service implements IBackgroundService {

private Timer timer ;

private BackgroundServiceBinder binder ;


private List<IBackgroundServiceListener> listeners = null;

@Override
public void onCreate() {
timer = new Timer();
binder = new BackgroundServiceBinder(this);
_onStart();
}

@Override
public IBinder onBind(Intent intent) {
return binder;
}

public void _onStart(){


timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
if(listeners != null){
fireDataChanged(new Object());
}
}}, 0, 60000);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
_onStart();
return START_NOT_STICKY;
}

// Ajout d'un listener


public void addListener(IBackgroundServiceListener listener) {
if(listeners == null){
listeners = new ArrayList<IGoogleWeatherListener>();
}
listeners.add(listener);
}

// Suppression d'un listener


public void removeListener(IBackgroundServiceListener listener) {
if(listeners != null){
listeners.remove(listener);
}
}

// Notification des listeners


private void fireDataChanged(Object data){
if(listeners != null){
for(IBackgroundServiceListener listener: listeners){
listener.dataChanged(data);
}
}
}

4 sur 12 06/04/2011 19:11


Utiliser les services sous Android - Android - Le blog d'un dveloppeur http://blog.developpez.com/android23/p8571/android/creation-de-service/

@Override
public void onDestroy() {
this.listeners.clear();
this.timer.cancel();
}
}

Nous dfinissons le binder qui nous permettra de rcuprer l'instance de notre service :

public class BackgroundServiceBinder extends Binder{

private IBackgroundService service = null;

public BackgroundServiceBinder(IBackgroundService service) {


super();
this.service = service;
}

public IBackgroundService getService(){


return service;
}
};

L'avantage de l'interface IBackgroundService est de masquer les mthodes onCreate(), onBind()... et de ne proposer uniquement
addListener(), removeListener() et pourquoi pas d'autres mthodes mtiers.

Il nous reste nous connecter au service, accder aux mthodes exposes par l'interface et s'ajouter comme listener pour mettre jour
l'interface utilisateur :

Intent intent = new Intent(this,BackgroundService.class);

final IBackgroundServiceListener listener = new IBackgroundServiceListener() {


public void dataChanged(final Object data) {
MyActivity.this.runOnUiThread(new Runnable() {
public void run() {
// Mise jour de l'UI
}
});
}
};

ServiceConnection connection = new ServiceConnection() {


public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("BackgroundService", "Connected!");
IBackgroundService service = ((BackgroundServiceBinder)service).getService();
service.addListener(listener);
}

public void onServiceDisconnected(ComponentName name) {


Log.i("BackgroundService", "Disconnected!");
}
};

bindService(intent,connection, Context.BIND_AUTO_CREATE);

La connexion au service se fait via la mthode bindService (Intent service, ServiceConnection conn, int flags) de la classe Context dont
hrite Activity. L'argument flags peut prendre soit 0 soit Context.BIND_AUTO_CREATE pour forcer le service dmarrer, s'il ne l'est pas,
au moment de la connexion.

La partie sur les LocalService est termine. Je ne suis pas personnellement convaincu de leur intret. Les classes Service,
ServiceConnection, IBinder... sont relativement contraignantes, complexifient le code et n'offrent pas vraiment d'aide la ralisation de
services. Mais si un jour votre LocalService doit se transformer en RemoteService alors vous serez prets.

> Services distants (RemoteService)

>> Dclaration du service

Contrairement aux LocalService qui s'excutent dans le processus de l'application et plus particulirement dans le thread principal, les
RemoteService s'excutent dans un processus totalement diffrent de celui de votre application.

Afin que deux processus diffrents puissent communiquer et s'changer des donnes, Google a implment son IDL appel AIDL (Android
Interface Definition Language) pour dcrire les mthodes publiques et les donnes changes. Cette description se fait dans un fichier
.aidl qui devra tre connu des deux processus !

Pourront tre changes entre deux processus, seulement les types primitifs java (int, boolean, etc), les String, List, Map et
CharSequence. Pour des objects personnaliss, vous devrez implmenter l'interface Parcelable.

Un RemoteService peut tre sollicit par plusieurs applications diffrentes. C'est pourquoi je prfre le dporter dans un nouveau projet
Android sous Eclipse. Je conseille galement la ralisation d'une petite interface graphique avec deux boutons pour le dmarrer et
l'arrter. Si vous ne souhaitez pas crer un projet particulier, il faudra ajouter android:process=":remote" la dclaration de votre
service (<service>) dans le fichier AndroidManifest.xml.

Aprs avoir crer un projet BackgroundService (package de l'application com.android23.backgroundservice), nous crons notre service
com.android23.backgroundservice.service.BackgroundService le plus simple qui soit, avec un Timer et un objet Data:

public class BackgroundService extends Service {

private Timer timer ;


private BackgroundServiceBinder binder ;
private Data data;

@Override
public void onCreate() {

5 sur 12 06/04/2011 19:11


Utiliser les services sous Android - Android - Le blog d'un dveloppeur http://blog.developpez.com/android23/p8571/android/creation-de-service/

binder = new BackgroundServiceBinder(this);


timer = new Timer();
_onStart();
}

public void _onStart(){


timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
data = new Data(18, Data.Weather.ENSOLEILLE);
}
}, 0, 60000);
}

@Override
public void onDestroy() {
super.onDestroy();
this.binder = null;
this.timer.cancel();
}

@Override
public IBinder onBind(Intent intent) {
return binder;
}

public Data getData() {


return data;
}
}

Pour chaque RemoteService il est ncessaire de dclarer un fichier .aidl que nous plaons dans le mme package
(com.android23.backgroundservice.service).

Voici le contenu de notre fichier IRemoteBackgroundService.aidl :

package com.android23.backgroundservice.service;

import com.android23.backgroundservice.bo.Data;

interface IRemoteBackgroundService {
int getPid(); // Renvoie le PID du processus du service
Data getData(); // Renvoie notre objet mis jour
//void updateData(in Data data);
}

Il n'y pas de rgle concernant le nom du fichier. Ce fichier sert d'interface entre le client et le service. Nous y dclarons seulement les
mthodes public. La syntaxe ressemble fortement au Java bien que cela n'en soit pas. Les mots clefs 'in', 'out', 'inout' sont ajouts aux
paramtres des mthodes. '//' permet d'ajouter des commentaires. Enfin on peut spcifier 'oneway' devant interface.

Nous crons dans le package com.android23.backgroundservice.bo, notre objet java Data implmentant l'interface Parcelable :

public class Data implements Parcelable {


public static enum Weather {NUAGEUX,PLUVIEUX,ENSOLEILLE,BROUILLARD}
private int temperature;
private Weather today;

public static final Parcelable.Creator<Data> CREATOR = new Parcelable.Creator<Data>() {


public Data createFromParcel(Parcel in) {
return new Data(in);
}

public Data[] newArray(int size) {


return new Data[size];
}
};

public Data(int temperature, Weather today) {


super();
this.temperature = temperature;
this.today = today;
}

public int getTemperature() {


return temperature;
}

public Weather getToday() {


return today;
}

private Data(Parcel in) {


readFromParcel(in);
}

public void readFromParcel(Parcel in) {


temperature = in.readInt();
today = (Weather)in.readSerializable();
}

public int describeContents() {


return 0;
}

public void writeToParcel(Parcel arg0, int arg1) {


arg0.writeInt(temperature);
arg0.writeSerializable(today);
}

6 sur 12 06/04/2011 19:11


Utiliser les services sous Android - Android - Le blog d'un dveloppeur http://blog.developpez.com/android23/p8571/android/creation-de-service/

Notre objet contient le temps et la temprature, deux types java simples. Le code est calqu sur l'exemple que vous trouverez sur
http://developer.android.com/guide/developing/tools/aidl.html.

L'interface Parcelable nous oblige dfinir la mthode writeToParcel() dans laquelle nous ajoutons l'objet Parcel tous les attributs de
notre objet Data. Un Parcel peut tre vue comme l'unit de communication entre deux processus. Attention, l'ordre dans lequel nous
ajoutons les attributs une importance. C'est ordre doit tre respect dans la mthode readFromParcel().

L'attribut static CREATOR est obligatoire. Il implmente l'interface Parcelable.Creator. L'implmentation de cette interface nous force a
crire la mthode readFromParcel().

Pour que notre objet Data puisse voyager d'un processus l'autre, il nous reste dclarer son fichier Data.aidl :

package com.android23.backgroundservice.bo;
parcelable Data;

Le mot clef parcelable spcifie que notre objet Data implmente bien le protocole Google pour les communication IPC.

Les erreurs contenues dans les fichiers .aidl devraient disparaitre. Eclipse gnre alors l'interface Java IRemoteBackgroundService dans
le rpertoire source "gen" du projet :

Il nous reste ensuite dclarer notre BackgroundServiceBinder qui permettra au client d'accder aux mthodes dclares dans le
fichier aidl. Notre binder hrite de IRemoteBackgroundService.Stub gnr par Eclipse :

public class BackgroundServiceBinder extends IRemoteBackgroundService.Stub{

private BackgroundService service = null;

public BackgroundServiceBinder(BackgroundService service) {


super();
this.service = service;
}

public Data getData() throws RemoteException {


return service.getData();
}

public int getPid() throws RemoteException {


return Process.myPid();
}
};

N'oublions pas de dclarer notre service dans le fichier AndroidManifest.xml :

<application android:icon="@drawable/icon" android:label="@string/app_name">


<service android:exported="true" android:name=".service.BackgroundService" />
</application>

Il est possible d'ajouter une permission :

<permission android:name="com.android23.backgroundservice.BACKGROUNDSERVICE_PERMISSION" />


<application android:icon="@drawable/icon" android:label="BackgroundService">
<service android:exported="true" android:enabled="true"
android:name=".service.BackgroundService"
android:permission="com.android23.backgroundservice.BACKGROUNDSERVICE_PERMISSION"/>
</application>

Les clients devront dclarer cette permission dans leur fichier manifest pour se connecter au service. Sans quoi une SecurityException
sera leve l'appel des mthodes startService ou bindService. Pour plus d'informations concernant les permissions, jetez un coup
d'oeil la documentation Google:

http://developer.android.com/guide/topics/manifest/manifest-intro.html#perms
http://developer.android.com/guide/topics/security/security.html

Revenons notre projet Eclipse principal. Pour raliser notre appel distant au service, nous devons y copier/coller les fichier .aidl
Data.aidl, et IRemoteBackgroundService.aidl dans le mme package que le projet BackgroundService, ainsi que votre objet java
Data! Eclipse crera automatiquement les interfaces d'accs.

Pour nous connecter au service, rien de bien compliqu :

Intent intent = new Intent();


intent.setClassName("com.android23.backgroundservice",
"com.android23.backgroundservice.service.BackgroundService");

ServiceConnection remoteConnection = new ServiceConnection() {


public void onServiceDisconnected(ComponentName name) {
}

public void onServiceConnected(ComponentName name, IBinder service) {


IRemoteBackgroundService service = IRemoteBackgroundService.Stub.asInterface(service);
try {
service.getPid();
service.getData();
} catch (RemoteException e) {
// TODO Auto-generated catch block
}
}
};

bindService(intent, remoteConnection, Context.BIND_AUTO_CREATE);

Nous passons au constructeur de l'Intent le package principal de notre projet BackgroundService puis la classe du service.
IRemoteBackgroundService.Stub.asInterface() nous permet de rcuprer notre service. A noter galement que chaque appel de
mthode peut lever une RemoteException.

Pour nous dconnecter au service, nous faisons appel la mthode unbindService(ServiceConnection) qui prend en paramtre
l'object ServiceConnection que nous avons cr :

7 sur 12 06/04/2011 19:11


Utiliser les services sous Android - Android - Le blog d'un dveloppeur http://blog.developpez.com/android23/p8571/android/creation-de-service/

unbindService(remoteConnection);

Il est indispensable d'ajouter la permission dans le fichier AndroidManifest.xml, au mme niveau que la balise <application> sans
quoi notre Activity ne se connectera jamais :

<uses-permission android:name="com.android23.backgroundservice.BACKGROUNDSERVICE_PERMISSION"></uses-
permission>

Il n'est pas possible de dbugger la fois le service et notre application. Pour tester, notre service il sera ncessaire de dvelopper dans
notre projet BackgroundService une Activity avec 2 boutons : un pour dmarrer le service, et l'autre pour l'arrter.
Pour tester notre application, nous dployons le service en premier puis nous lanons notre application en mode debug.

>> Mise en place d'un syteme de Callback/Listeners

Comme pour les LocalService, les RemoteService peuvent galement notifier leurs clients grce une liste RemoteCallbackList. Pour cela
nous allons apporter quelques modifications.

Pour commencer, retournons dans le projet BackgroundService, et modifions le fichier IRemoteBackgroundService.aidl en supprimant
la mthode getData() et en rajoutant les mthodes registerCallback et unregisterCallback qui permettrons aux clients de
s'enregistrer auprs du service :

package com.android23.backgroundservice.service;

import com.android23.backgroundservice.service.IRemoteBackgroundServiceCallback;

interface IRemoteBackgroundService {

int getPid();

void registerCallback(IRemoteBackgroundServiceCallback cb);


void unregisterCallback(IRemoteBackgroundServiceCallback cb);
}

A travers cette interface, les clients pourront s'enregistrer. Une fois enregistrs il leur faudra implmenter l'interface
IRemoteBackgroundServiceCallback que nous dclarons dans le fichier IRemoteBackgroundServiceCallback.aidl :

package com.android23.backgroundservice.service;

import com.android23.backgroundservice.bo.Data;

interface IRemoteBackgroundServiceCallback {
void dataChanged(in Data data);
}

Nous dclarons dans notre service, la liste des clients l'coute :

final RemoteCallbackList<IRemoteBackgroundServiceCallback> callbacks = new


RemoteCallbackList<IRemoteBackgroundServiceCallback>();

public RemoteCallbackList<IRemoteBackgroundServiceCallback> getCallbacks() {


return callbacks;
}

Nous mettons jour la mthode _onStart() afin de crer un nouvel objet Data toutes les minutes et notifier les clients :

public void _onStart() {


Log.i(getClass().getSimpleName(), "_onStart()");
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
data = new Data(++counter, Data.Weather.BROUILLARD);

// Broadcast to all clients the new value.


final int N = callbacks.beginBroadcast();
for (int i = 0; i < N; i++) {
try {
callbacks.getBroadcastItem(i).dataChanged(data);
}
catch (RemoteException e) {}
}
callbacks.finishBroadcast();
}
}, 0,60000);
}

callbacks.beginBroadcast() et callbacks.finishBroadcast(); encadre le dbut et la fin de la notification des clients.


callbacks.getBroadcastItem(i) vous permet d'appeler les mthodes de l'intarface IRemoteBackgroundServiceCallback et prvenir les
clients. Elle ne peut tre appele qu'aprs beginBroadcast()

Nous dsactivons la liste des callbacks dans la mthode onDestroy() :

@Override
public void onDestroy() {
super.onDestroy();
this.binder = null;
this.callbacks.kill(); // Dsactive tous les lments de la liste
this.timer.cancel();
}

N'oublions pas de mettre jour notre Binder implmentant l'interface IRemoteBackgroundService.Stub :

public class BackgroundServiceBinder extends IRemoteBackgroundService.Stub{

private BackgroundService service = null;

public BackgroundServiceBinder(BackgroundService service) {


super();

8 sur 12 06/04/2011 19:11


Utiliser les services sous Android - Android - Le blog d'un dveloppeur http://blog.developpez.com/android23/p8571/android/creation-de-service/

this.service = service;
}

@Override
public int getPid() throws RemoteException {
return Process.myPid();
}

@Override
public void registerCallback(IRemoteBackgroundServiceCallback cb) throws RemoteException {
if(cb != null){
service.getCallbacks().register(cb);
}

@Override
public void unregisterCallback(IRemoteBackgroundServiceCallback cb) throws RemoteException {
if(cb != null){
service.getCallbacks().unregister(cb);
}
}
};

Retournons maintenant du ct de notre application principale pour y copier les fichiers IRemoteBackgroundService.aidl et
IRemoteBackgroundServiceCallback.aidl dans le package com.android23.backgroundservice.service.

Puis mettons jour la manire dont nous nous connectons au service en dclarant un IRemoteBackgroundServiceCallback et en
l'inscrivant auprs du service dans la mthode onServiceConnected() :

Intent intent = new Intent();


intent.setClassName("com.android23.backgroundservice",
"com.android23.backgroundservice.service.BackgroundService");

final IRemoteBackgroundServiceCallback callback = new IRemoteBackgroundServiceCallback.Stub() {


public void dataChanged(Data data) throws RemoteException {
Log.d( getClass().getSimpleName(), "Temperature : " + data.getTemperature());
Log.d( getClass().getSimpleName(), "Temps : " + data.getToday().toString());
}
};

ServiceConnection remoteConnection = new ServiceConnection() {


public void onServiceDisconnected(ComponentName name) {
Log.d( getClass().getSimpleName(), "onServiceConnected()" );
}

public void onServiceConnected(ComponentName name, IBinder service) {


remoteBackgroundService = IRemoteBackgroundService.Stub.asInterface(service);
try {
remoteBackgroundService.getPid();
remoteBackgroundService.registerCallback(callback);
}
catch (RemoteException e) {}
}
};

bindService(intent, remoteConnection, Context.BIND_AUTO_CREATE);

Pour tester, nous dployons le service et puis nous lanons en mode debug notre application.

>> Dmarrer le service au boot du tlphone

Dans le projet BackgroundService, nous rajoutons un BroadcastReceiver :

public class BackgroundServiceReceiver extends BroadcastReceiver{


@Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent();
serviceIntent.setClassName("com.android23.backgroundservice",
"com.android23.backgroundservice.service.BackgroundService");
context.startService(serviceIntent);
}
}

Nous le rajoutons dans le fichier AndroidManifest.xml :

<permission android:name="com.android23.backgroundservice.BACKGROUNDSERVICE_PERMISSION" />

<application android:icon="@drawable/icon" android:label="@string/app_name">

<service android:exported="true" android:name=".service.BackgroundService"


android:permission="com.android23.backgroundservice.BACKGROUNDSERVICE_PERMISSION" />

<receiver android:name=".service.BackgroundServiceReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</receiver>
</application>

<uses-permission android:name="com.android23.backgroundservice.BACKGROUNDSERVICE_PERMISSION"/>

Nous avons galement prcis que notre service demande la permission BACKGROUNDSERVICE_PERMISSION pour pouvoir dmarrer tout
seul.

Dployons le service sur l'mulateur en faisant un clic droit sur le projet : Run As > Android Application. Une fois dploy, re-dmarrons

9 sur 12 06/04/2011 19:11


Utiliser les services sous Android - Android - Le blog d'un dveloppeur http://blog.developpez.com/android23/p8571/android/creation-de-service/

l'mulateur en cliquant sur le bouton dans la barre d'outil d'Eclipse puis sur le bouton start dans la fentre qui apparait. Une fois
l'mulateur lanc, il suffit d'aller dans Menu > Settings > Applications > Running Services > pour constater que notre
BackgroundService est bien en route.

>> Exemple : Connexion au service MP3

Le lecteur MP3 d'Android est lui aussi un RemoteService. Il est donc trs simple de s'y connecter pour rcuprer la chanson en cours,
l'artiste... Pour l'exemple n'oubliez pas de lancer la lecture d'un fichier mp3.

Profitons du fait qu'Android soit open-source pour nous rendre sur Google Code et rcuprer le fichier IMediaPlaybackService.aidl.

Une fois le fichier rcupr, nous crons le package "com.android.music" dans lequel nous insrons le fichier .aidl. Eclipse gnre alors
automatiquement l'interface IMediaPlaybackService. Le service ne renvoyant que des types primitifs, seul ce fichier suffit au client.

Nous nous connectons au lecteur mp3 comme nous nous connections notre BackgroundService :

Intent intent = new Intent();


intent.setClassName("com.android.music", "com.android.music.MediaPlaybackService");

ServiceConnection conn = new ServiceConnection() {


@Override
public void onServiceDisconnected(ComponentName componentname) {
}

@Override
public void onServiceConnected(ComponentName componentname, IBinder ibinder) {
IMediaPlaybackService service = IMediaPlaybackService.Stub.asInterface(ibinder);

try {
Log.i("ServiceConnection", "Playing track: " + service.getTrackName());
Log.i("ServiceConnection", "By artist: " + service.getArtistName());
} catch (Exception e) {
}

}
};

this.bindService(intent, conn, 0);

Malheureusement, si Google modifie l'interface .aidl de son lecteur MP3 il faudra mettre jour le fichier IMediaPlaybackService.aidl
dans notre projet.

> Conclusion

Le post est relativement long mais regroupe tout ce que j'ai pu apprendre en parcourant le net. Je vais rflchir le publier au format
PDF dans la rubrique tutorial.

L'intrt des LocalService reste flou mes yeux. J'ai la fcheuse impression de gagner plus en complexit qu'en productivit. A contrario,
les RemoteService ont une vritable valeur ajoute. Ainsi on peut imaginer un service mto commun toutes nos applications et nos
widgets. Les possibilits sont nombreuses ds lors que l'OS gre le multi-taches :D :D :D

Si vous souhaitez que certains points soient approfondis, ou corrigs, n'hsitez pas m'en faire part.

> Ressources

http://developer.android.com/reference/android/app/Service.html
http://blog.7touchgroup.com/tag/android-services-versus-broadcast-receivers/
http://www.brighthub.com/mobile/google-android/articles/34861.aspx
http://saigeethamn.blogspot.com/2009/09/android-developer-tutorial-part-9.html
http://www.androidcompetencycenter.com/2009/06/start-service-at-boot/
http://www.alexc.me/android-music-app-service-currently-playing-song/231/

Commentaires:

Commentaire de: Nicolas Druet [Membre]


"Les services s'excutent dans le Thread principal du processus parent"
C'est pourquoi on cre un thread dans le localService. Ainsi avoir un vrai tche de fond. Mais qui sera dtruite quand l'application

10 sur 12 06/04/2011 19:11


Utiliser les services sous Android - Android - Le blog d'un dveloppeur http://blog.developpez.com/android23/p8571/android/creation-de-service/

sera ferme.

"Les services distants (ou RemoteService) qui s'excutent dans un processus diffrent de celui de application"
Tout a fait. Mais en aucun cas son processus parent est le processus de l'application. Sinon ca n'aurait pas grand intrt. Le
RemoteService est une autre application Android sans IHM ;)

30/05/2010 @ 22:32

11 sur 12 06/04/2011 19:11


Utiliser les services sous Android - Android - Le blog d'un dveloppeur http://blog.developpez.com/android23/p8571/android/creation-de-service/

Vous devez tre identifi pour poster un commentaire.

Responsable bnvole de la rubrique Blogs : - Contacter par email

Vos questions techniques : forum d'entraide Blogs - Publiez vos articles, tutoriels et cours
et rejoignez-nous dans l'quipe de rdaction du club d'entraide des dveloppeurs francophones
Nous contacter - Hbergement - Participez - Copyright 2000-2011 www.developpez.com - Legal informations.

12 sur 12 06/04/2011 19:11

Você também pode gostar