IUT de Lannion
Dept Informatique
Programmation Android
TP6 - Bases de données
P. Nerzic
2016-17
1. Base de données SQLite
Dans ce TP, nous allons voir comment créer et utiliser une base de données SQL locale pour
stocker les informations. La semaine prochaine, ça sera avec un WebService.
On repart de l’application AvosAvis de la semaine précédente. . . quelque soit son état d’avancement.
Vous pouvez même repartir de la version de base, AvosAvis.zip, mais évidemment la vôtre
1
sera
plus complète.
Faites une copie du projet
AvosAvis
et appelez-la
AvosAvisSQL
, puis travaillez uniquement sur
cette copie.
1.1. Essais en ligne de commande (optionnels)
Lancez un AVD (pas la tablette réelle, car
sqlite3
n’y est pas installé en tant que programme
utilisateur). Relisez le TP1 en ce qui concerne la connexion en shell avec la commande
adb
.
Connectez-vous en shell sur l’AVD.
NB: il peut y avoir un bug. Si vous n’arrivez pas à vous connecter à la tablette, alors tapez :
adb kill-server
adb start-server
adb devices
Dans le shell de la tablette, lancez la commande
sqlite3
sans paramètre. En faisant ainsi, ce
qu’on va créer ne sera qu’en mémoire vive, pas enregistré dans un fichier. Faites-vous la main avec
quelques requêtes SQL et directives spécifiques de SQLite :
CREATE TABLE Loisirs (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
nom TEXT NOT NULL);
.schema Loisirs
INSERT INTO Loisirs VALUES (1,'sport');
INSERT INTO Loisirs VALUES (2,'informatique');
INSERT INTO Loisirs VALUES (null,'cinéma');
INSERT INTO Loisirs VALUES (null,'santé');
.dump Loisirs
SELECT *FROM Loisirs;
.headers on
SELECT nom FROM Loisirs WHERE _id=3;
.dump Loisirs
UPDATE Loisirs SET nom='ordinateur'WHERE _id=2;
DELETE FROM Loisirs WHERE nom='santé';
SELECT *FROM Loisirs ORDER BY nom ASC;
.exit
Notez que l’identifiant d’une table doit TOUJOURS être un entier appelé
_id
. Si on fournit
null
1
Ne copiez pas le projet d’un autre étudiant, ce serait très peu apprécié. Demandez plutôt de l’aide. Le but,
c’est que vous appreniez quelque chose, pas que le TP semble fini.
1
IUT de Lannion
Dept Informatique
Programmation Android
TP6 - Bases de données
P. Nerzic
2016-17
en tant qu’identifiant alors SQLite en attribue un automatiquement. C’est le rôle de l’option
AUTOINCREMENT (SERIAL dans PostgreSQL).
1.2. Table Avis
On va commencer par définir une classe
TableAvis
qui représente la table Avis (libellé, note,
auteur et date). Relisez le cours de la semaine 6, notamment le transparent intitulé « Classe pour
une table ». L’idée, c’est que cette classe va remplacer le ArrayList des TPs précédents.
Complétez les méthodes de la classe TableAvis (cherchez les TODO) :
void create(SQLiteDatabase bdd)
Cette méthode effectue la création de la table dans la base de données. Elle exécute une
requête
CREATE TABLE Avis...
à l’aide de la méthode
execSQL
sur le paramètre
bdd
. Les
attributs de la table sont :
_id de type INTEGER PRIMARY KEY AUTOINCREMENT
libelle de type TEXT NOT NULL
note de type REAL
auteur de type TEXT
date de type INTEGER. Remarque : le type LONG ou TIMESTAMP n’existe pas.
void drop(SQLiteDatabase bdd)
Cette méthode supprime totalement la table
Avis
de la base. Utiliser la méthode
execSQL
.
NB: utilisez l’option IF EXISTS afin de parer aux erreurs de double suppression.
Long insertAvis(SQLiteDatabase bdd, Avis avis)
Cette méthode ajoute l’avis indiqué à la table
Avis
. Vous avez deux manières de le faire.
Soit utiliser la méthode
execSQL
, soit utiliser la méthode
insert
. La seconde est à préférer
car elle retourne l’identifiant du nouveau n-uplet. Il pourrait être repris pour créer une
relation, en tant que clé étrangère dans une autre table.
La méthode
insert
est plus compliquée que
execSQL
car il faut créer un
ContentValues
et mettre les colonnes dedans. Relisez le cours, transparents « Exemples de méthodes » et
« Méthode insert ». Regardez aussi les accesseurs de la classe Avis.
En ce qui concerne la date, on vous suggère d’utiliser la méthode
getTimestamp
de l’avis.
Le principe est de transformer la date en un nombre de millisecondes écoulées depuis le
01/01/1970. Ça s’appelle un timestamp et si vous devez travailler avec des dates, vous
passerez beaucoup de temps à convertir des timestamps en date et vice-versa. Beaucoup de
SGBD possèdent les types DATE,TIME,DATETIME et TIMESTAMP, mais pas sqlite3.
void updateAvis(SQLiteDatabase bdd, Long id, Avis avis)
Cette méthode modifie le n-uplet identifié par
id
. En fait, c’est presque la même méthode
que la précédente, mais on fait
UPDATE
au lieu de
INSERT
et il faut fournir une clause de
sélection. Vous pouvez également soit utiliser
execSQL
, soit
update
. Relisez le cours. Si
vous utilisez update, n’oubliez pas de convertir l’identifiant en chaîne.
void deleteAvis(SQLiteDatabase bdd, Long id)
Cette méthode supprime le n-uplet identifié par id.
2
IUT de Lannion
Dept Informatique
Programmation Android
TP6 - Bases de données
P. Nerzic
2016-17
Avis getAvis(SQLiteDatabase bdd, Long id)
Cette méthode retourne un nouvel objet
Avis
construit à partir du n-uplet identifié par
id
. Elle crée un curseur, effectue une requête par
rawQuery
et extrait les colonnes qu’elle
place dans un nouvel avis retourné en résultat, puis elle ferme le curseur. La création d’un
Avis
à partir d’un curseur se fait avec une méthode statique de la classe
TableAvis
appelée
fromCursor qu’on vous invite à aller voir.
1.3. Helper pour gérer la base de données
L’étape suivante consiste à créer un helper pour gérer la base de données. Vous avez juste à
compléter celui qui est fourni, comme dans le cours : rajoutez-lui l’appel qui crée la table Avis et
celui qui supprime la table. Vous comprenez que dans une application ayant plusieurs tables, il
faudrait mettre tous les appels aux fonctions de création nécessaires et dans le bon ordre pour
respecter les contraintes de clés étrangères.
1.4. Nettoyage
Avant d’attaquer la suite, vous allez supprimer la classe
AvosAvisApplication
et enlever l’attribut
android:name
de l’application dans le manifeste. Cela va causer un grand nombre d’erreurs dans
MainActivity
et
EditActivity
: chaque fois que vous utilisez encore l’ancienne liste. On va les
supprimer peu à peu.
1.5. MainActivity
Maintenant, l’objectif est de supprimer partout le
ArrayList
global de l’application et de mettre
des appels aux méthodes de
TableAvis
à la place. Il y a quelques transformations pour remplacer
le ArrayList par la base SQL.
Variables membres :
Rajoutez deux variables membres :
MySQLiteHelper helper;
SQLiteDatabase bdd;
Changer le type de la variable membre
adapter
en
CursorAdapter
. Ça va entraîner
de nouvelles erreurs tant que tout n’est pas cohérent.
Méthode
onCreate
, devinez ce qu’il faut faire des deux membres
helper
et
bdd
. La réponse
est donnée dans le cours, transparent intitulé « Utilisation du Helper dans l’application ».
La base doit être ouverte en écriture si vous avez mis en place le menu contextuel, sinon en
lecture quand l’activité ne modifie jamais les données.
Complétez la méthode onDestroy de l’activité en rajoutant la fermeture du helper.
Méthode
onCreate
encore, vous pourrez tester deux adaptateurs différents (un seul à la
fois) :
Le type SimpleCursorAdapter :
adapter = new SimpleCursorAdapter(
this,
3
IUT de Lannion
Dept Informatique
Programmation Android
TP6 - Bases de données
P. Nerzic
2016-17
android.R.layout.simple_list_item_2,
null,
new String[]{TableAvis.Libelle, TableAvis.Note},
new int[]{android.R.id.text1, android.R.id.text2},
0);
C’est un adaptateur qui affiche les champs dans un layout standard d’Android. Il ne
peut afficher que deux chaînes, un titre et un sous-titre. La note est automatiquement
convertie en texte.
Le type AvisCursorAdapter :
adapter = new AvisCursorAdapter(this,null, R.layout.item_avis);
C’est un adaptateur dérivé de CursorAdapter similaire au AvisAdapter du TP4.
Toujours dans
onCreate
, il faut créer un chargeur de curseur et le démarrer. Ça se fait avec
cette ligne à la fin de la méthode, après avoir ouvert la base de données et créé l’adapter :
getLoaderManager().initLoader(AVIS_LOADER_ID, null,this);
Vous allez avoir une erreur quand vous ferez ça, car il faudrait que
this
implémente une
interface. Allez voir dans le cours le transparent intitulé « Activité ou fragment d’affichage
d’une liste ». Les méthodes de cette interface sont déjà programmées, vous devez seulement
rajouter l’interface nécessaire à la liste
implements
. Attention, AndroidStudio vous propose
deux packages possibles pour importer
Loader
et
LoaderManager
, il ne faut pas prendre ceux
concernant appcompat, mais
android.app.LoaderManager
et
android.content.Loader
.
Mise à jour de la liste : à la place des
adapter.notifyDataSetChanged()
, mettre ce qui
suit. Si c’est dans un écouteur, alors vous devez mettre le nom de la classe englobante devant
this :
getLoaderManager().restartLoader(AVIS_LOADER_ID, null,this);
Repérez toutes les lignes marquées TODO et faites ce qui est indiqué : décommenter la
ligne suivante et parfois supprimer la suivante. Pour toutes les méthodes surchargées, vous
pouvez décommenter l’annotation @Override.
1.6. EditActivity
Comme dans
MainActivity
, il faut remplacer les actions sur le
ArrayList
global par des requêtes
SQL à travers la classe TableAvis.
Variables membres :
Rajoutez deux variables membres :
MySQLiteHelper helper;
SQLiteDatabase bdd;
et recopiez les mêmes instructions pour ouvrir la base, cette fois toujours en écriture.
Complétez la méthode onDestroy en rajoutant la fermeture du helper.
4
IUT de Lannion
Dept Informatique
Programmation Android
TP6 - Bases de données
P. Nerzic
2016-17
Il faut maintenant remplacer les accès au
ArrayList
par un accès à la base. Par exemple,
dans la méthode display :
// récupérer l'item désigné par l'identifiant
Avis avis = TableAvis.getAvis(bdd, identifiant);
C’est la méthode
valider
qui vous posera le plus de problèmes pour comprendre exactement
ce qu’il faut faire, dans quel ordre et ce qui change par rapport à la liste.
1.7. Réflexion
Un problème de réflexion pour finir : comment pourrait-on organiser les classes s’il y avait une
deuxième table dans la base ? Actuellement, il n’y a que la table
Avis
, mais si on rajoute une
table
Categories
contenant des catégories d’avis comme repas, sorties, sports, études. . . ; cette
catégorie étant une clé étrangère dans la table Avis. Il faudrait créer une classe
TableCategories
avec ses requêtes comme dans TableAvis.
Cela paraît assez simple si c’est une relation 1-n(un avis a une et une seule catégorie, mais une
catégorie peut concerner plusieurs avis). Lors de la création de la base de données, il faut appeler
la méthode de création des deux tables dans le bon ordre. Ensuite, l’un des traitements est l’ajout
d’un avis ayant une nouvelle catégorie, il faut insérer la catégorie, récupérer son identifiant puis
insérer l’avis. À moins d’avoir une activité spécifiquement pour gérer les catégories et qu’on ne
puisse pas créer de catégorie dans un avis mais seulement choisir parmi les existantes.
Mais si la relation est du type n-n(un avis peut avoir plusieurs catégories et une catégorie peut
concerner plusieurs avis), représentée par une autre table (
CategoriesAvis
), comment pourrait-on
organiser les classes et quelles méthodes elles pourraient contenir (question ouverte) ?
2. Travail à rendre
Avec le navigateur de fichiers, descendez dans le dossier app/src du projet AvosAvis du TP6.
Rajoutez un fichier appelé exactement
IMPORTANT.txt
dans le sous-dossier
main
si vous avez
rencontré des problèmes techniques durant le TP : plantages, erreurs inexplicables, perte du travail,
etc. mais pas les problèmes dus à un manque de travail ou de compréhension. Décrivez exactement
ce qui s’est passé. Le correcteur pourra lire ce fichier au moment de la notation et compenser
votre note.
Cliquez droit sur le dossier
main
, choisissez
Compresser...
, format
tar.gz
, cliquez sur
Creer
.
Déposez l’archive main.tar.gz sur Moodle au bon endroit.
5
1 / 5 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !