Académique Documents
Professionnel Documents
Culture Documents
I) Présentation
Les services font partie des briques essentielles d’Android. Ils ne disposent pas d’interface
utilisateur mais fonctionnent en arrière-plan pour une période de temps indéfinie. L’exemple
le plus courant est le lecteur de musique, qui permet d’écouter sans bloquer l'activité.
Les services s’exécutent dans le Thread principal du processus parent. Ils doivent être
déclarés dans le fichier AndroidManifest.xml par :
<service android:name=".subpackagename.ServiceName"/>
1
Deux possibilités pour interagir avec un service (demarrer/arrêter…) :
La méthode startService() qui invoque la méthode onCreate() puis
onStart().
service.startService() -> onCreate() – > onStartCommand() [service running]
Remarque
Il est possible de voir la liste des services exécutés du téléphone :
Menu > Settings > Applications > Running Services
Les services personnalisés sont lancés à partir d'autres composants Android, à savoir
des activités, des récepteurs de diffusion et d'autres services.
2
Ensuite la méthode onStartCommand(Intent intent, int flags, int
startId) sera lancée avec les arguments suivants :
- intent: l'intent qui a été utilisé pour lancer la requête au service (pourra être null
dans le cas d'une relance du service suite à un arrêt de celui-ci).
- Flags : permet de savoir plus sur la nature de l'intent qui a lancé le service, il vaut :
0 s'il n'y a rien de spécial à dire.
START_FLAG_REDELIVERY si l'intent avait déjà été délivré et qu'il l'est à nouveau
parce que le service avait été interrompu.
START_FLAG_RETRY si le service redémarre alors qu'il s'était terminé de manière
anormale.
- startId : permet d'identifier le lancement (1 pour le premier lancement, 2
pour le deuxième lancement, etc.).
-
Remarque
flags est un paramètre qui peut avoir en même temps START_FLAG_REDELIVERY et
START_FLAG_RETRY.
Cette méthode retourne un entier qui détermine ce que fera le système si le service est tué :
START_NOT_STICKY
Si le système tue le service, alors ce dernier ne sera pas recréé. Il faudra donc effectuer un
nouvel appel à startService().
START_STICKY
Si le service est tué, alors il sera recréé mais sans avoir le dernier Intent qui l'avait lancé. Le
paramètre intent vaudra null.
START_REDELIVER_INTENT
Le service sera recréé et dans onStartCommand() le paramètre intent sera indiqué au dernier
intent qui a été fourni au service. Le paramètre START_REDELIVER_INTENT est
indispensable pour qu'un service effectue un travail complètement.
Arrêter un service
Pour arrêter un service, il faudra appeler la méthode stopSelf() si le
service veut s'arrêter lui-même ou stopService(Intent serv)depuis
une activité. serv est l'intent fournie lors de l’appel startService()
correspondant.
Passage d'informations
Généralement un service a besoin de communiquer pour effectuer un
traitement, le principe de passage d'informations sera le même que
pour les activités. On utilisera les extras ou les datas avec les intents.
Exemple
Déclarer le service
3
Au début, il faut déclarer le service dans le Manifest. Il faut préciser certains attributs
android:name : identifiant,
android:icon : un drawable qui jouera le rôle d'icône,
android:permission : pour créer une permission nécessaire à l'exécution du service
android:process pour préciser dans quel processus se lancera ce service.
Exemple
<service
android:name="MusicService"
android:process=":player" >
…
</service>
En Java
Démarrer un service explicitement : startService().
Il existe deux classes mères principales qui permettent de créer un service, Service et
IntentService.
Exemple: créer une application contenant deux boutons, le premier lance le service et l'autre
l'arrête.
Le service
public class IntentServiceExample extends Service {
MediaPlayer myPlayer;
@Override
public void onCreate() {
Toast.makeText(this, "Service was Created", Toast.LENGTH_LONG).show();
myPlayer = MediaPlayer.create(this, R.raw.sun);
myPlayer.setLooping(false); // Set looping
}
public IBinder onBind(Intent intent) {
return null;
}
4
}
@Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
myPlayer.stop();
}}
L'activité principale
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onClick(View view) {
startService(new Intent(getBaseContext(), IntentServiceExample.class));
//intent.putExtra("KEY1", "Value to be used by the service");
}
public void onClick (View view) {
stopService(new Intent(getBaseContext(), IntentServiceExample.class));
}}
Cette classe est facile à gérer puisque il suffit d'implémenter la méthode void
onHandleIntent(Intent intent) qui recevra toutes les requêtes dans l'ordre sous la
forme d'intent, ainsi qu'un constructeur qui fait appel au constructeur
d'IntentService.
Syntaxe :
public class ExampleService extends IntentService {
public ExampleService() {
super("Nom_du_service"); }
protected void onHandleIntent(Intent intent) {
// Gérer la requête
}}
On peut aussi implémenter les autres méthodes de callback, mais on doit toujours appeler leur
super implémentation, sinon le service échouera :
public int onStartCommand(Intent intent, int flags, int startId) {
// Du code
return super.onStartCommand(intent, flags, startId);
}
Exemple1
5
Une activité envoie un chiffre à un IntentService qui va l'afficher dans la console.
De plus, l'IntentService fera un long traitement pour que chaque fois que l'activité
envoie un chiffre les intents s'accumulent, ce qui fera que les messages seront retardés dans la
console.
mBouton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(MainActivity.this, IntentServiceExample.class);
i.putExtra("code", mCompteur);
mCompteur ++;
mAffichageCompteur.setText("le compteur vaut " + mCompteur);
startService(i);
}});
}}
Le bouton fait incrémenter le compteur et envoie un intent qui lance un service qui s'appelle
IntentServiceExample. L'intent est ensuite reçu et traité.
Le service
public class IntentServiceExample extends IntentService {
private final static String TAG = "IntentServiceExample";
public IntentServiceExample() {
super(TAG);
}
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "Le compteur valait:" + intent.getIntExtra("code",-1));
long i = 0;
//Cette boucle permet de rajouter artificiellement du temps de traitement
while(i < 1000L)
i++;
}}
6
Pour transférer des données entre un service et une activité, nous devons
utiliser un LocalBroadcastManager.
Dans cet exemple, nous allons créer une application qui passe une chaîne à un
IntentService qui la renvoie à l'activité après un délai. Grâce à IntentService, cela se
produit de manière séquentielle.
Exemple 2
public class MainActivity extends AppCompatActivity {
TextView textView;
Button button;
EditText editText;
MyReceiver myReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
button = findViewById(R.id.button);
editText = findViewById(R.id.inputText);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String message = editText.getText().toString();
Intent intent = new Intent(MainActivity.this, MyService.class);
intent.putExtra("message", message);
startService(intent);
}
});
}
@Override
protected void onStart() {
myReceiver = new MyReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(FILTER_ACTION_KEY);
LocalBroadcastManager.getInstance(this).registerReceiver(myReceiver, intentFilter);
super.onStart();
}
@Override
protected void onStop() {
unregisterReceiver(myReceiver);
7
super.onStop();
}
@Override
protected void onHandleIntent(Intent intent) {
String message = intent.getStringExtra("message");
intent.setAction(MainActivity.FILTER_ACTION_KEY);
SystemClock.sleep(3000);
String echoMessage = "IntentService after a pause of 3 seconds" + message;
LocalBroadcastManager.getInstance(getApplicationContext()).
sendBroadcast(intent.putExtra("broadcastMessage", echoMessage));
}
}
Pour assurer une connexion avec le service on utilise la méthode boolean bindService(Intent service,
ServiceConnection conn, int flags).
conn : permet de recevoir le service quand celui-ci démarrera et permet de savoir s'il meurt ou s'il
redémarre (ServiceConnection est une interface qui surveille l'exécution du service distant). Il existe deux
méthodes de callback à redéfinir :
1. void onServiceConnected(ComponentName name, IBinder service) appelée quand la connexion au
service est établie, avec un IBinder qui correspond à un canal de connexion avec le service.
IBinder : est un pont entre votre service et l'activité mais se trouve au niveau du service.
Les IBinder permettent au client de faire des demandes au service.
8
La méthode onBind doit renvoyer un type de IBinder propre à votre service, ce qui signifie que vous
devez créer votre propre implémentation de l’interface IBinder.
Le service sera créé s'il n'était pas déjà lancé (appel à onCreate()), mais ne passera pas par
onStartCommand().
Pour qu'on puisse se détacher d'un service, on utilise la méthode unbindService(ServiceConnection conn) .
Exemple
public class MainActivity extends AppCompatActivity {
private MyService MonService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnexion);
}
9
private ServiceConnection mConnexion = new ServiceConnection() {
// Méthode appelée lorsque la connexion est établie. Récupère la référence vers le service associé.
public void onServiceConnected(ComponentName className, IBinder service) {
MonService = ((MyService.MonServiceBinder) service).getService();
}
// Méthode appelée lorsque la connexion est rompue.
public void onServiceDisconnected(ComponentName className) {
mMonService = null;
}};
}
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
C'est un jeton que vous donnez à une application étrangère qui permet à cette application
étrangère d'utiliser les permissions de votre application pour exécuter un morceau de code
prédéfini.
L'application recevant un PendingIntent, aura les droits d'effectuer une opération comme s'il
s'agissait de l'application émettrice (avec les mêmes permissions et la même identité).
Pour des raisons de sécurité, l'intention de base fournie à PendingIntent doit avoir le
nom du composant explicitement défini pour garantir qu'il est finalement envoyé à
cette application et nulle part ailleurs.
On aura deux applications : celle de départ et celle d'arrivée. L'application d'arrivée peut alors
effectuer des opérations dans l'application source (avec les mêmes permissions et la même
identité). Il faut alors donner à l'application d'arrivée tous les renseignements et toutes les
autorisations nécessaires pour qu'elle puisse demander à l'application de départ d'exécuter une
action à sa place.
Pour le faire, on insère dans le PendingIntent un autre Intent, qui décrit l'action. Le seul but
du PendingIntent est d'être véhiculé entre les deux applications.
10
- PendingIntent.getBroadcast(Context context, int requestCode, Intent
intent, int flags) : Récupère un PendingIntent pour effectuer une diffusion.
Exemple : // Intent explicite qui sera utilisé pour lancer à nouveau MainActivity
Notification
Toast
Par défaut, Android affiche le message en bas de l’écran de l’utilisateur. Ce comportement peut être
redéfini pour en changer la position. Vous pouvez spécifier la disposition d’un toast en spécifiant son
ancrage sur l’écran ainsi qu’un décalage sur l’axe horizontal et vertical.
Exemple
Toast toast = Toast.makeText(this, "Vous prendrez bien un toast ou deux ;",
Toast.LENGTH_LONG);
toast.setGravity(Gravity.TOP, 0, 40); // Spécifie la dispostion du Toast sur l’écran
toast.show();// Affichage du Toast
Les notifications
La plate-forme Android fournit et exécute des services système prédéfinis et toutes les
applications Android peuvent les utiliser, avec les autorisations appropriées.
11
Ces services système sont généralement exposés via une classe de gestionnaire
spécifique. Leur accès peut être obtenu via la méthode getSystemService().
La classe Context définit plusieurs constantes pour accéder à ces services.
Un service nous avertit de l'arrivée des évènements avec des notifications dans la barre de statut
(ou avec des Toasts).
Le gestionnaire de notifications
Pour pouvoir utiliser le gestionnaire de notifications dans votre application, vous devez
récupérer l’instance du service des notifications du système Android par la méthode
getSystemService avec le paramètre Context.NOTIFICATION_SERVICE.
NotificationManager nm = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
Une fois l’instance du gestionnaire de notifications récupérée, on peut gérer les notifications
en termes d’ajout, de suppression et de modification.
2) Propriétés de la notification
Une fois on a un objet Builder, on peut définir ses propriétés de notification à l'aide de l'objet Builder selon les
besoins. Mais ceci est obligatoire pour définir au moins :
Une petite icone : setSmallIcon()
Un titre : setContentTitle()
Le Détail : setContentText()
mBuilder.setSmallIcon(R.drawable.notification_icon);
mBuilder.setContentTitle("Notification Alert, Click Me!");
mBuilder.setContentText("Hi, This is Android Notification Detail!");
L'action est définie par un PendingIntent contenant un Intent qui démarre une activité dans votre application.
12
Pour associer un PendingIntent à un geste, appelez la méthode appropriée de NotificationCompat.Builder. Par
exemple, si vous voulez démarrer Activité lorsque l'utilisateur clique sur le texte de notification dans le tiroir de
notification, vous ajoutez l'élément PendingIntent en appelant setContentIntent().
Un objet PendingIntent vous aide à effectuer une action au nom de vos applications, souvent plus tard, sans se
soucier de savoir si votre application est en cours d'exécution ou non.
Nous prenons l'aide de l'objet générateur de pile stack Builder qui contiendra une pile arrière pour l'activité
démarrée. Cela garantit que la navigation en arrière de l'activité mène hors de votre application vers l'écran
d'accueil.
4) Envoyer la notification
On peut passer l'objet Notification au système en appelant la méthode
NotificationManager.notify() pour envoyer la notification. Assurez-vous que vous
appelez la méthode NotificationCompat.Builder.build() sur l'objet Builder avant de
le notifier. Cette méthode combine toutes les options qui ont été définies et
renvoie un nouvel objet Notification.
Exemple
public class SettingsActivity extends AppCompatActivity {
NotificationCompat.Builder notification_builder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout1);
13
} else {
notification_builder = new NotificationCompat.Builder(this);
}
notification_builder.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Notification Title")
.setContentText("Notification Body")
.setAutoCancel(true)
.setContentIntent(contentIntent)
.build();
notificationManager.notify(0, notification_builder);
} }
14