Vous êtes sur la page 1sur 15

13/11/2018

04 PROGRAMMATION CONCURRENTE

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL

PROGRAMMATION CONCURRENTE
Composants d'une application

 La boite de dialogue, appelée Application Not Responding (ANR) informe l'utilisateur


que l'application ne semble plus répondre. Deux choix se présentent à l'utilisateur :
> Attendre en espérant que l'application “reprenne ses esprits” et commence à
répondre …
> Forcer la fermeture de l'application. Ce choix radical consiste à tuer le processus
dans lequel s'exécute l'application. Les données non sauvegardées sont alors
perdues et l'exécution du programme s'arrête purement et simplement.

 Une application Android n'est pas qu'une simple activité. Dans de nombreux cas, une
application Android est amenée à tirer partie de la programmation:
> Des threads
> AyncTask
> Des services
> Des IntentService

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 2

1
13/11/2018

PROGRAMMATION CONCURRENTE
Vie des processus

 Android peut devoir arrêter un processus à cause d'autres processus qui requièrent
plus d'importance. Par exemple, un service peut être détruit car une application
gourmande en ressources (navigateur web) occupe de plus en plus de mémoire. Plus
classiquement, le processus affecté à une activité qui n'est plus visible a de grandes
chances d'être détruit.

 Ainsi, une hiérarchie permet de classer le niveau d'importance des processus:


> Processus en avant plan (activité en interaction utilisateur, service attaché à cette
activité, BroadCastReceiver exécutant onReceive())
> Processus visible: il n'interagit pas avec l'utilisateur mais peut influer sur ce que l'on
voit à l'écran (activité ayant affiché une boite de dialogue (onPause() a été appelé),
service lié à ces activité "visibles").
> Processus de service
> Processus tâche de fond (activité non visible (onStop() a été appelé))
> Processus vide (ne comporte plus de composants actifs, gardé pour des raisons
de cache)

 Il faut préférer l'utilisation d'un service à la création d'un thread pour accomplir une
tâche longue, par exemple l'upload d'une image. On garantit ainsi d'avoir le niveau 3
pour cette opération, même si l'utilisateur quitte l'application ayant initié l'upload.

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 3

PROGRAMMATION CONCURRENTE

 Type de traitements concurrents

Thread JobIntentService

Les services

IntentService AyncTask

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 4

2
13/11/2018

PROGRAMMATION CONCURRENTE
Thread

 Dans le processus principal, le système crée un thread d'exécution pour l'application:


le thread principal. Il est, entre autre, responsable de l'interface graphique et des
messages/notifications/événements entre composants graphiques. Par exemple,
l'événement générant l'exécution de onKeyDown() s'exécute dans ce thread.

 Ainsi, si l'application doit effectuer des traitements longs, elle doit éviter de les faire
dans ce thread. Cependant, il est interdit d'effectuer des opérations sur l'interface
graphique en dehors du thread principal (aussi appelé UI thread), ce qui se résume
dans la documentation sur les threads par deux règles:
> Do not block the UI thread
> Do not access the Android UI toolkit from outside the UI thread

 L'exemple à ne pas faire est donné dans la documentation et recopié ci-dessous. Le


comportement est imprévisible car le toolkit graphique n'est pas thread-safe.

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 5

PROGRAMMATION CONCURRENTE
Threads et interface graphique

 Android fournit des méthodes pour résoudre le probème précédemment évoqué. Il


s'agit de créer des objets exécutables dont la partie affectant l'interface graphique n'est
pas exécutée mais déléguée à l'UI thread pour exécution ultérieure.
 Par exemple, un appel à la méthode View.post(Runnable) permet de réaliser cela et
donne, pour l'exemple précédent:

 D’autre Méthodes
sont disponibles:
> Activity.runOnUiThread(Runnable)
> View.post(Runnable)
> View.postDelayed(Runnable, long)

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 6

3
13/11/2018

PROGRAMMATION CONCURRENTE
AyncTask
 AsyncTask permet une utilisation correcte et facile du thread UI. Cette classe vous permet
d'effectuer des opérations en background et de publier des résultats sur le main thread sans
avoir à manipuler les threads et / ou handlers.

 Pour executer l’AsyncTask

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 7

PROGRAMMATION CONCURRENTE
Les Services

 La structure d'une classe de service ressemble à une activité. Pour réaliser un service,
on hérite de la classe Service et on implémente les méthodes de
création/démarrage/arrêt du service. La nouvelle méthode qu'il faut implémenter ici
est onBind qui permet de faire des appels à des méthodes distantes.

 Le service se déclare dans le Manifest dans le tag application:


COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 8

4
13/11/2018

PROGRAMMATION CONCURRENTE
Créer un service

 Pour créer un service, il faut sélectionner le package dans lequel on souhaite créer le
service, et ensuite on va dans le menu: File  New  Service  Service

 L’option enabled permet l’instantiation ou non du service


 L’option exported accorde à d’autres applications de lancer le service

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 9

PROGRAMMATION CONCURRENTE
Démarrer / Arrêter un service

 Les Intents fournissent un moyen de démarrer/arrêter un service en utilisant le nom de


la classe du service ou un identifiant d'action:

 Ces méthodes sont à invoquer dans l'activité de l'application développée. On dit alors
que le service est local à l'application: il va même s'exécuter dans le thread de
l'application. Un bouton de démarrage d'un service local est simple à coder:

L’exemple ci-dessus montre une demande de démarrage de service


en mode Intent implicite (on n’a pas spécifié à démarrer)
COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 10

5
13/11/2018

PROGRAMMATION CONCURRENTE
Auto démarrage d'un service

 Il est aussi possible de faire démarrer un service au démarrage du système. Pour cela,
il faut créer un BroadcastReceiver qui va réagir à l'action BOOT_COMPLETED et
lancer l'Intent au travers de la méthode startService.

 Le Manifest contient donc:

 Et la classe AutoStart doit être:

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 11

PROGRAMMATION CONCURRENTE
IntentService

 Un autre design pattern a été simplifié dans Android: l'exécution dans un processus
isolé de jobs provenant d'une autre partie de l'application. Les jobs sont provisionnés
au travers d'un Intent et l'IntentService exécute la tâche dans la
méthode onHandleIntent(), indépendamment de l'UI thread.

 IntentService est une classe de base pour les services qui gèrent des requêtes
asynchrones (exprimées en intentions) à la demande

 Les clients envoient des demandes via les appels startService (Intent)

 Le service est démarré selon les besoins, gère chaque intention à son tour à l'aide d'un
thread de travail et s'arrête automatiquement lorsqu'il est à court de travail.

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 12

6
13/11/2018

PROGRAMMATION CONCURRENTE
JobIntentService (Android 8.0)

 Helper pour le traitement du travail qui a été mis en file d'attente pour un Job/service.
 Lors de l'exécution sur Android O ou version ultérieure, le travail sera distribué en tant
que travail via JobScheduler.enqueue. Lors de l'exécution sur les anciennes versions
de la plate-forme, il utilisera Context.startService.
 Vous devez publier votre sous-classe dans votre manifeste pour le système avec
lequel interagir. Cela devrait être publié en tant que JobService, comme décrit pour
cette classe, car sur les plates-formes O et ultérieures, il sera exécuté de cette façon.

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 13

PROGRAMMATION CONCURRENTE

Service Thread IntentService AsyncTask

 Comparaison - Tâche longue


généralement sans
communication avec le - Tâche relativement
thread principal.(Mise à longue (blocage de
Tâche sans interface -Longue tâche en général. jour) thread UI) avec un
utilisateur, mais ne devrait - Si une communication besoin de communiquer
pas être trop longue. - Pour les tâches en est requise, peut utiliser avec le thread principal.
Quand utiliser ?
Utilisez les threads au sein parallèle, utiliser plusieurs le gestionnaire de
du service pour les longues threads (mécanismes threads principal ou les - Pour les tâches en
tâches. traditionnels) intentions de diffusion parallèle, utilisez
- Quand les rappels sont plusieurs instances OU
nécessaires (tâches Executor
déclenchées par
l'intention).
Appeler via la méthode
Déclenché par La méthode start() Intent La méthode execute()
onStartService()
Main Thread (Intent est
reçu sur le thread principal,
Déclenché à partir N’importe quel thread N’importe quel thread Main Thread
puis le thread de travail est
généré)
Worker Thread. Toutefois,
les méthodes de thread
Tourne sur Main Thread Son propre thread Thread séparé principal peuvent être
invoquées entre publier la
progression.
- une instance ne peut
- Impossible d’executer des être exécutée qu'une
- Gestion de threads
taches en parallèle seule fois (elle ne peut
manuels
Limitations / Peut bloquer le thread donc pas être exécutée
inconvénients principal - Plusieurs intentions sont en boucle)
- Le code pourrait devenir
mises en file d'attente sur le - Doit être créé et exécuté
difficile à lire/maintenir
même worker thread. à partir du thread
principal

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 14

7
13/11/2018

05 ANDROID:
PERSISTANCE DE DONNÉES

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL

PERSISTANCE DE DONNÉES

 Android fournit plusieurs méthodes pour faire persister les données applicatives:
> la persistance des données de l'activité
> un mécanisme de sauvegarde clé/valeur, utilisé pour les fichiers de préférences
(appelé préférences partagées)
> des entrées sorties de type fichier
> une base de donnée basé sur SQLite

 La persistance des données des activités est géré par l'objet Bundle qui permet de
restaurer les View qui possède un id. S'il est nécessaire de réaliser une sauvegarde
plus personnalisée, il suffit de recoder les
méthodes onSaveInstanceState et onCreate et d'utiliser les méthodes qui permettent
de lire/écrire des données sur l'objet Bundle

 Android fournit aussi automatiquement, la persistance du chemin de navigation de


l'utilisateur, ce qui le renvoie à la bonne activité lorsqu'il appuie sur la touche Retour.
La navigation vers le parent (bouton "up") n'est pas automatique car c'est le concepteur
qui doit décider vers quelle activitée l'application doit retourner quand on appuie sur
"up". Elle peut être programmée dans le Manifest avec l'attribut
android:parentActivityName.

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 16

8
13/11/2018

PERSISTANCE DE DONNÉES

SharedPreferences SQlite

Sauvegarde des
Les fichiers
activité

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 17

PERSISTANCE DE DONNÉES
SharedPreferences

 La classe SharedPreferences permet de gérer des paires de clé/valeurs associées à


une activité.

 Utile voire indispensable pour un grand nombre d'applications, pouvoir enregistrer les
paramètres des utilisateurs

 Le point de départ de la manipulation des préférences partagées est la


classe SharedPreferences. Elle possède des méthodes permettant d'enregistrer et
récupérer des paires de type clé-valeur pour les types de données primitifs, comme les
entiers ou les chaînes de caractères.

 L'avantage réel étant bien sûr que ces données sont conservées même si l'application
est arrêtée ou tuée.

 Ces préférences sont de plus accessibles depuis plusieurs composants au sein d'une
même application.

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 18

9
13/11/2018

PERSISTANCE DE DONNÉES
SharedPreferences

 Il existe trois façons d'avoir accès aux SharedPreferences:


> La plus simple est d'utiliser la méthode statique:

> Si vous désirez utiliser un fichier standard par activité, alors vous pourrez utiliser la
méthode:

> si vous avez besoin de plusieurs fichiers que vous identifierez par leur nom, alors
utilisez

 En ce qui concerne le second paramètre, mode, il peut prendre trois valeurs :


> Context.MODE_PRIVATE, pour que le fichier créé ne soit accessible que par
l'application qui l'a créé.
> Context.MODE_WORLD_READABLE, pour que le fichier créé puisse être lu par
n'importe quelle application.
> Context.MODE_WORLD_WRITEABLE, pour que le fichier créé puisse être
lu et modifié par n'importe quelle application.

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 19

PERSISTANCE DE DONNÉES
Editeur SharedPreferences

 Afin d'ajouter ou de modifier des couples dans un SharedPreferences, il faut utiliser un


objet de type SharedPreference.Editor. Il est possible de récupérer cet objet en utilisant
la méthode SharedPreferences.Editor edit() sur un SharedPreferences.
 Si vous souhaitez ajouter des informations, utilisez une méthode du put qui convient le
type à persister:
> SharedPreferences.Editor putX(String key, X value) avec X le type de
l'objet, key l'identifiant et value la valeur associée. Il vous faut ensuite impérativement
valider vos changements avec la méthode boolean commit()

 Pour récupérer une valeur, on peut utiliser la méthode


> X getX(String key, X defValue) avec X le type de l'objet désiré, key l'identifiant de votre
valeur et defValue une valeur que vous souhaitez voir retournée au cas où il n'y ait pas de
valeur associée à key

Pour la méthode get il faut indiquer une valeur par défaut à utiliser si
la clé est introuvable
COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 20

10
13/11/2018

PERSISTANCE DE DONNÉES
Editeur SharedPreferences

 Si vous souhaitez supprimer une préférence, vous pouvez le faire avec:


> SharedPreferences.Editor remove(String key)

 Pour supprimer toutes les préférences, il existe aussi:


> SharedPreferences.Editor clear()

 Si vous voulez récupérer toutes les données contenues dans les préférences, vous
pouvez utiliser la méthode:
> Map<String, ?> getAll()

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 21

PERSISTANCE DE DONNÉES
Des préférences prêtes à l'emploi

 Pour enregistrer vos préférences, vous pouvez très bien proposer une activité qui
permet d'insérer différents paramètres.

 Il est fortement conseillé d’utiliser une interface de gestion de configuration qui modifie
visuellement les préférences partagé.

 Pour développer son propore activity de gestion de préférences, il suffit d’hériter de la


classe PreferenceActivity)

 chaque couple identifiant/valeur est créé


automatiquement et sera récupéré automatiquement,
d'où un gain de temps énorme dans la programmation.
La création se fait en plusieurs étapes,
nous allons voir la première,
qui consiste à établir une interface graphique en XML.

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 22

11
13/11/2018

PERSISTANCE DE DONNÉES
SharedPreferences –> PreferenceActivity: Le XML

 La première étape consiste à définir le XML pour l’acitivté de gestion de préférence.


Comme ce n’est pas vraiment un layout on le définit dans le repertoire
/xml/preference.xml.

 La racine de ce fichier doit être un PreferenceScreen

 il est possible de désigner des catégories de préférences. Une pour les préférences
destinées à internet par exemple, une autre pour les préférences esthétiques, etc. On
peut ajouter des préférences avec le nœud PreferenceCategory. Ce nœud est un
layout, il peut donc contenir d'autre vues. Il ne peut prendre qu'un seul
attribut, android:title, pour préciser le texte qu'il affichera.

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 23

PERSISTANCE DE DONNÉES
SharedPreferences –> PreferenceActivity: le XML

 Pour insérer des préférences à l’intérieur des catégories, il faut inserer des composants
XML de type Xpreference comme: CheckPreferences, EditTextPRefeces,
ListPreference…

 Les préférences ont cinq attributs en commun:


> android:key est l'identifiant de la préférence partagée. C'est un
attribut indispensable, ne l'oubliez jamais.
> android:title est le titre principal de la préférence.
> android:summary est un texte secondaire qui peut être plus long et qui explique
mieux ce que veut dire cette préférence.
> Utilisez android:dependency, si vous voulez lier votre préférence à une autre
activité. Il faut y insérer l'identifiant android:key de la préférence dont on dépend.
> android:defaultValue est la valeur par défaut de cette préférence.

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 24

12
13/11/2018

PERSISTANCE DE DONNÉES
SharedPreferences –> PreferenceActivity: le XML

 Une entrée de préférence peut être liée à une liste de paires de clef-valeur dans les
ressources:

 qui se déclare dans le menu de préférences:

 Lorsque l'on choisit la valeur "Petite", la préférence vitesse est associée à "1 »
COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 25

PERSISTANCE DE DONNÉES
SharedPreferences –> PreferenceActivity: Le Manifest et le Java

 Pour recevoir cette nouvelle interface graphique, nous avons besoin d'une activité. Il
nous faut donc la déclarer dans le Manifest si on veut pouvoir y accéder avec les
intents. Cette activité sera déclarée comme n'importe quelle activité :

 Notre activité sera en fait de type PreferenceActivity. On peut la traiter comme une
activité classique, sauf qu'au lieu de lui assigner une interface graphique
avec setContentView, on utilise void addPreferencesFromResource(int
preferencesResId) en lui assignant notre layout :

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 26

13
13/11/2018

PERSISTANCE DE DONNÉES
Les Fichiers
 Android fournit aussi un accès classique au système de fichier pour tous les cas qui ne
sont pas couverts par les préférences ou la persistance des activités. Le choix de
Google est de s'appuyer sur les classes classiques de Java EE tout en simplifiant la
gestion des permissions et des fichiers embarqués dans l'application.

 Pour la gestion des permissions, on retrouve comme pour les préférences les
constantes MODE__PRIVATE et MODE_WORLD_READABLE/WRITABLE à passer
en paramètre de l'ouverture du fichier. En utilisant ces constantes comme un masque,
on peut ajouter | MODE_APPEND pour ajouter des données.

 Les ressources permettent aussi de récupérer un fichier embarqué dans l'application:

les fichier sont à éviter. Mieux vaut alléger l'application au maximum


et prévoir le téléchargement de ressources nécessaires et l'utilisation
de fournisseurs de contenu.
COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 27

PERSISTANCE DE DONNÉES
SQLite
 Android dispose d'une base de donnée relationnelle basée sur SQLite. Même si la base doit être
utilisée avec parcimonie, cela fournit un moyen efficace de gérer une petite quantité de données.
 Voici un exemple de création de base de données, ce qui se fait en héritant de SQLiteOpenHelper:

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 28

14
13/11/2018

PERSISTANCE DE DONNÉES
Instanciation / Lecture / Ecriture dans la BDD

 Instancier la classe de BDD  Consulter une base de donnees


SQLITE

 Ecrire dans SQLITE

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 29

PERSISTANCE DE DONNÉES
Lecture / Ecriture dans la BDD

 Pour réaliser des écritures ou lectures, on utilise les


méthodes getWritableDatabase() et getReadableDatabase() qui renvoient une instance
de SQLiteDatabase. Sur cet objet, une requête peut être exécutée au travers de la
méthode query():

 L'objet de type Cursor permet de traiter la réponse (en lecture ou écriture), par
exemple:
> getCount(): nombre de lignes de la réponse
> moveToFirst(): déplace le curseur de réponse à la première ligne
> getInt(int columnIndex): retourne la valeur (int) de la colonne passée en paramètre
> getString(int columnIndex): retourne la valeur (String) de la colonne passée en
paramètre
> moveToNext(): avance à la ligne suivante
> getColumnName(int): donne le nom de la colonne désignée par l'index

COURS DÉVELOPPEMENT MOBILE 2018-2019 ENSA KENITRA – UNIVERSITÉ IBN TOUFAIL 30

15

Vous aimerez peut-être aussi