Android,
A Complete Course, From
Basics to Enterprise Edition
Android, A Complete Course, From Basics to Enterprise Edition
1 Mon application est un Service
Cet
article est extraie du livre « Android, A Complete Course »,
disponible sur Android2ee.com.
Les
exemples ou les programmes présents dans cet ouvrage sont fournis pour
illustrer les descriptions théoriques. Ce code est libre de toute utilisation
mais n'est pas distribuable.
La
distribution du code est reservée au site :
La
propriété intellectuelle du code appartient à :
L’utilisation
de ces codes est sous votre unique responsabilité et personne d’autre que vous
ne pourra être tenu responsable des préjudices ou dommages de quelques natures
que ce soit pouvant résulter de son utilisation.
Tous les
noms de produits ou marques cités dans cet ouvrage sont des marques déposés par
leurs propriétaires respectifs.
Publié par http://android2ee.com
Titre Original : Android, A Complete Course, From
Basics to Enterprise Edition. Édition Française.
ISBN : 979-10-90388-00-0
Copyright © 2011 by Mathias Séguy
Aucune
représentation ou reproduction, même partielle, autre que celles prévues à
l’article L. 122-5 2° et 3° a) du code de la propriété intellectuelle ne peut
être faite sans l’autorisation expresse de Mathias Seguy ou, le cas échéant,
sans le respect des modalités prévues à l’article L. 122-10 dudit code
Un service, c’est un démon, une thread qui tourne sans IHM, bref un service. Un service est un singleton ou presque. En effet, si plusieurs processus accèdent au service, il n’y aura qu’un service. Mais si le service n’a plus d’utilisateur alors le singleton est détruit et le prochain utilisateur recrée un autre singleton. Cela paraît anodin, mais si votre service lance une thread puis est détruit et recréé alors il lancera une nouvelle thread, oubliant la précédente…
L’exemple typique d’un service est votre lecteur de musique. Quand le lecteur n’est plus au premier plan, la musique continue à être jouée, c’est un service. Si ce n’était qu’une activité, dés que l’activité aurait quitté le premier plan, la musique se serait arrêtée.
Un service se lance soit manuellement par l’utilisateur, soit par un appel d’un autre processus. Puis, il reste en vie jusqu'à ce qu’il ne soit plus nécessaire. De ce fait, il doit être très peu gourmant en CPU (au risque de vider la batterie trop vite) et en mémoire (au risque de saturer l’appareil trop vite).
Enfin, soit votre service est interne à votre application et n’a pas de vocation à être ouvert sur le reste du système, soit il a pour vocation d’être ouvert au système. Ces deux cas de figure sont profondément différents et dans l’implémentation et dans l’utilisation du service. Nous n’exposerons ici que le cas d’un service ouvert au reste du monde.
Il faut implémenter sept choses dans votre Activity pour pouvoir utiliser un service:
· Un objet Service qui n’est autre qu’un pointeur vers le service que vous souhaitez utiliser.
·
Un objet ServiceConnection dont le
but est de gérer la connexion et la déconnexion au service.
· Un objet BroadCastReceiver pour pouvoir écouter les modifications envoyées par le service
· Un appel à la méthode bindService(service, serviceConnection, flags) dans votre méthode onCreate
· Un appel à la méthode unbindService(serviceConnection) dans votre méthode onDestroy
· Un appel à la méthode registerReceiver(broadcastReceiver, filter) dans votre méthode onResume pour pouvoir écouter les intentions envoyées par le service. Ce mécanisme permet au service d’informer l’activité d’un changement.
· Un appel à la méthode unregisterReceiver(broadcastReceiver) dans votre méthode onPause pour stopper l’écoute des modifications envoyées par le service.
Ce qui donne l’exemple élémentaire suivant :
public class
MyServiceUser extends Activity {
/**
* The service that can be used as a normal
object You can call its public methods
*/
private
MyService appService
= null;
/**
* The broadcast receiver that aims to listen
to change broadcast by the service
*/
private
BroadcastReceiver receiver
= new
BroadcastReceiver() {
public void
onReceive(Context context, Intent intent) {
// Do something, call a method, you already know your
service
// you can use its methods directly in your code
}
};
/**
* The service connection, that aims to connect
to the service
*/
private
ServiceConnection onService
= new
ServiceConnection() {
/* (non-Javadoc)
*
@see
android.content.ServiceConnection#onServiceConnected(android.content.ComponentName,
* android.os.IBinder)
*/
public void
onServiceConnected(ComponentName className, IBinder rawBinder) {
appService =
((MyService.LocalBinder) rawBinder).getService();
}
/* (non-Javadoc)
* @see
*
android.content.ServiceConnection#onServiceDisconnected(android.content.ComponentName)
*/
public void
onServiceDisconnected(ComponentName className) {
appService = null;
}
};
@Override
public
void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
...
//Bind
your service to your activity.
//The
parameters are: The intent to talk to the service, the service connection
//to
use and a flag to indicates if the service has to automaticly start or not
//You
should use BIND_AUTO_CREATE
bindService(new
Intent(this,
MyService.class),onService,
Context.BIND_AUTO_CREATE);
}
@Override
public void
onResume() {
super.onResume();
//Register your activity to listen for change send by
the service
//You can here see that the service has
declared a Static public String BROADCAST_ACTION //that is used to identify the
Intent with unicity
registerReceiver(receiver, new
IntentFilter(MyService.BROADCAST_ACTION));
}
@Override
public void
onPause() {
super.onPause();
//Unregister your activity to listen for change send
by the service
unregisterReceiver(receiver);
}
@Override
public void
onDestroy() {
super.onDestroy();
//Unbind your service (else your activity will be
destroyed but your service
//will still think that somebody use it
unbindService(onService);
}
}
Lors de la création d’un service, gardez en tête que celui-ci s’exécute par défaut dans la thread principale de votre application. C’est à vous de faire en sorte de créer une thread pour que votre service l’utilise et ne court-circuite pas votre activité principale.
Pour créer un service, vous devez implémenter :
· la méthode onCreate() qui a à charge l’initialisation
· la méthode onDestroy qui a à charge la destruction de votre service
· une classe privée qui étend Binder
· la méthode onBind qui renvoie votre classe privée qui étend Binder
· un attribut public static final qui n’est autre que votre identifiant d’intention
· la classe de traitement dans une thread parallèle pour effectuer les actions de votre service. Cette classe étend AsyncTask.
/**
* @author
mathias1
* @goals
This class aims to show a service's skeleton
*/
public class
MyService extends Service {
/*****************************************************************************************/
/**
Managing initialisation and death
***************************************************/ /*****************************************************************************************/
/*
* (non-Javadoc)
*
* @see
android.app.Service#onCreate()
*/
@Override
public void onCreate() {
super.onCreate();
//initialize
your service here
}
/*
* (non-Javadoc)
*
* @see android.app.Service#onDestroy()
*/
@Override
public void onDestroy() {
super.onDestroy();
//destroy
your service here
}
/****************************************************************************************/
/**
Managing the binder to this
service*********************************************************/ /****************************************************************************************/
/**
* The binder that glue to my
service
*/
private final Binder binder=new LocalBinder();
/**
* @author
mSeguy
* @goals
This class aims to define the binder to use for my service
*/
public class LocalBinder extends Binder {
/**
* @return the
service you want to bind to : i.e. this
*/
MyService getService() {
return (MyService.this);
}
}
/* (non-Javadoc)
* @see
android.app.Service#onBind(android.content.Intent) */
@Override
public IBinder onBind(Intent intent) {
return binder;
}
/*****************************************************************************************/
/**
Managing the Communication between the service and its listeners
**********************/
/****************************************************************************************/
/**
* The key of the Intent to
communicate with the service's users
*/
public static final String MY_SERVICE_INTENT = "stinfoservices.net.android.MyUniqueItentServiceKey";
/**
* The intent itself
*/
private Intent broadcast = new Intent(MY_SERVICE_INTENT);
/**
* @author
mSeguy
* @goals
* This class aims to make a
task in a separeted thread
*/
class MyTaskInAnOtherThread extends
AsyncTask<Location, Void, Void> {
@Override
protected Void doInBackground(Location... locs) {
//
Do something to update your data
// here
is the place where your treatment is done in another thread than in the GUI
//
thread
//
Prevent your listener that something happens
sendBroadcast(broadcast);
return (null);
}
@Override
protected void onProgressUpdate(Void... unused) {
//
not needed here
}
@Override
protected void onPostExecute(Void unused) {
// not needed here
}
}
}
Le fichier manifest.xml est décrit de manière complète à la page :
http://developer.android.com/guide/topics/manifest/manifest-intro.html
Ce fichier est le centre névralgique de votre application et ce pour plusieurs raisons :
· D’une part il décrit les besoins de votre application, en termes de SDK, de compatibilité matérielle, d’API utilisées et d’utilisation de services du système,
· D’autre part, il décrit ce qu’offre votre application au système (Activity, ContentProvider, Service…),
· Enfin, il décrit les éléments auxquels votre application réagit au moyen des IntentFilters et d’URI ainsi que les permissions nécessaire pour les utiliser.
Ce fichier est analysé par les markets pour cibler les appareils qui sont éligibles pour le téléchargement de votre application. Il faut donc être très attentif à sa mise en place.
Pour décrire ces éléments, ce fichier possède la structure globale suivante :
<manifest>
<uses-permission />
<permission />
<permission-tree />
<permission-group />
<instrumentation />
<uses-sdk />
<uses-configuration />
<uses-feature />
<supports-screens />
<compatible-screens />
<supports-gl-texture />
<application>
<activity>
<intent-filter>
<action />
<category />
<data />
</intent-filter>
<meta-data />
</activity>
<activity-alias>
<intent-filter> . . . </intent-filter>
<meta-data />
</activity-alias>
<service>
<intent-filter> . . . </intent-filter>
<meta-data/>
</service>
<receiver>
<intent-filter> . . . </intent-filter>
<meta-data />
</receiver>
<provider>
<grant-uri-permission />
<meta-data />
</provider>
<uses-library />
</application>
</manifest>
N’hésitez pas à assouvir votre curiosité en
allant sur la page précédemment citée pour connaître chacune de ces balises.