Android
Persistance
? Persistance
Garder une trace des interactions avec l’utilisateur
et conserver des données d’une session à une autre…
Toute application doit pouvoir charger et
enregistrer des données.
Android propose plusieurs mécanismes pour gérer
la persistance, c’est-à-dire lire et écrire des
informations dont la durée de vie est supérieurs au
temps d’exécution du programme.
Persistance sous Android
Les solutions pour stocker les données sous Android sont:
Shared Preferences : stockage primitif sous forme
de mapping clé/valeur
Stockage dans des fichiers : stockage élémentaire
pour lire et écrire des données brutes dans le
système de fichiers d’Android
Bases de données SQLite : stockage de données
structurées
Données distantes : stockage via un serveur
SQLit
e
SQLite : Présentation
générale
SQLite est une base de données relationnelles
disponible sur tous les terminaux Android et le SDK
fournit des API permettant au développeur de
créer/gérer sa base de données privées.
Une application peut disposer de plusieurs bases de
données. Toutes les bases de données sont
sauvegardées sous :
/data/data/<package_name>/databases
Créé en MODE_PRIVATE, d’où le fait que seule
l’application l’ayant créé peut y accéder.
Le SDK dispose d’un outil permettant de manipuler les
bases de données du téléphone via une fenêtre de
commande
tools/sql3
? Why SQLite
• Zero-configuration :
• it requires no configuration file. It requires no installation steps or
initial setup; it has no server process running and no recovery steps
to take even if it crashes.
• There is no server and it is directly embedded in our application.
• no administrator is required to create or maintain a DB instance, or
set permissions for users.
• No-copyright : SQLite, instead of a license, comes with a blessing.
The source code of SQLite is in the public domain; you are free to
modify, distribute, and even sell the code.
? Why SQLite
• Cross-platform:
• Database flies from one system can be moved to a system : a This is possible
because the database file format is binary and all the machines use the same
format.
• Compact:
• An SQLite database is a single ordinary disk file; it comes without a server and
is designed to be lightweight and simple. : SQLite Version 3.7.8 has a
footprint of less than 350 KB.
• Fool proof :
• The code base is well commented, easy to understand, and modular.
• The test cases and test scripts in SQLite have approximately 1084 times more
code than the source code of SQLite library and they claim 100 percent
branch test coverage.
Ce qu’il lui manque
• Aucune gestion des utilisateurs (autorisations), pas de
sécurité.
• Pas de réglages pour améliorer les performances
• Peu de types de données, ex: date = entier ou chaîne,
un seul type d’entiers.
L’outil sqlite3 (Démonstration):
adb shell
cd /data/data
cd <nom_package>
Par exemple com.example.admin.bdd_light
cd databases
Sqlite3 <nom_de_la_bdd>
Par exemple DBContacts
Exécuter les requetes sql :
Par exemple pour voir tous les enregistrements :
select * from contacts
Où Contacts est le nom d’une table de la bdd
SQLite : Comment ça
marche
L’application embarque les commandes nécessaires pour la
manipulation de la base de données : création, suppression,….
Le développeur doit créer les scripts de création de la base de
données et les intégrer à l’application.
La base de donnée est automatiquement créée par le système
qui dispose d’un mécanisme permettant de vérifier l’état de la
base.
Lors du premier appel à la base, si celle-ci n’existe pas le
système exécutera alors les scripts de création des tables.
La base de données n’est pas créée tant qu’on y fait pas
référence.
SQLite : Packages et
Classes
SQLite : Packages et
Classes
Packages android.database.sqlite : Classes pour les
fonctionnalités liées à SQLite.
SQLiteOpenHelper : permet de manipuler les bases de
données SQLite : création, évolution…
onCreate() : à la création de la base
onUpgrade() : Evolution de la base
SQLiteDatabase :
Créer un objet qui pourra être utilisé pour ouvrir la base de
données en LECTURE/Écriture.
L'objet peut ensuite utiliser les opérations pour manipuler les
enregistrements dans la table de la base de données.
SQLite
: Les types de données supportées :
INTEGER : Valeur entière signée sur 1 à 8 bytes
REAL : Valeur flottante
TEXT : Chaine de caractère formatée (UTF-8, UTF-16BE or UTF-16LE)
NUMERIC: données blob stockées comme elle a été entrée
NONE : Type non précisé
SQLite propose un tableau d’affinité permettant de mapper un type
de données dans les langages avancés à l’un des types supportés
dans le framework.
INTEGER : INT , INTEGER, TINYINT, SMALLINT, MEDIUMINT, BIGINT, UNSIGNED
BIG INT, INT2, INT8
TEXT : CHARACTER(20) , VARCHAR(255), VARYING CHARACTER(255), NCHAR(55)
NATIVE CHARACTER(70), NVARCHAR(100), TEXT, CLOB
SQLite : Syntaxe SQL
CREATE TABLE Planetes (
_id INTEGER PRIMARY KEY AUTOINCREMENT, nom TEXT NOT
NULL, distance REAL, idType INTEGER NOT NULL, FOREIGN
KEY(idType) REFERENCES Types(_id));
SELECT* FROM Planete WHERE distance > 200.0 ORDER BY
distance;
SELECT AVG(distance) AS moyenne FROM Planetes GROUP BY
idType;
INSERT INTO Planetes Values (‘Terre’ , ’0 ’)
DELETE FROM Planetes WHERE distance IS NULL;
ALTER TABLE Planetes ADD COLUMN date INTEGER;
UPDATE Planetes SET date=strftime('%s','now');
DROP TABLE Planetes;
La méthode Query() :
La méthode query() prend en paramètre les parties
d’une instruction SELECT afin de construire la
requête. Ces différentes composantes apparaissent
dans l’ordre suivant dans la liste des paramètres :
Query : Liste des
Paramètre paramètres Commentaire
String dbName Le nom de la table pour laquelle la requête est compilée.
Une liste des colonnes à retourner. En passant "null", toutes les colonnes seront
String[] columnNames
retournées.
Clause "where", filtre pour la sélection des données, "null" permet de
String whereClause
sélectionner toutes les données.
Vous pouvez inclure des ? dans la "whereClause". Ces caractères génériques
String[] selectionArgs
(placeholders) seront remplacés par les valeurs du tableau selectionArgs.
Un filtre qui déclare comment regrouper les lignes, avec "null" les lignes ne
String[] groupBy
seront pas groupées.
String[] having Filtre pour les groupes, null signifie pas de filtrage.
Colonnes de la table utilisées pour ordonner les données, avec null les données
String[] orderBy
ne seront pas ordonnées.
SQLiteOpenHelper :
appelé à chaque requête d’accès à la base, elle est chargée de la
création et de la mise à jour de la BD.
On Crée une classe qui implémente SQLiteOpenHelper afin
d’indiquer au système la structure de la base de données de
l’application.
public class myDB extends SQLiteOpenHelper {
public myDB(Context context, String name, CursorFactory factory, int
version)
{ super(context, name, factory, version);}
@Override
public void onCreate(SQLiteDatabase db) {
//Script de Création de la base }
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{ // Script de Mise à jour de la base } }
Création d’une table dans la BDD
@Override
public void onCreate(SQLiteDatabase db)
{
String script = "CREATE TABLE categorie( " + " nom
TEXT, " +
"description TEXT" +
"id INTEGER PRIMARY KEY AUTOINCREMENT);";
db.execSQL(script);
}
SQLiteDatabase :
Classe permettant de manipuler une base de données SQLite.
Propose des méthodes génériques pour les requêtes
CRUD : Create, Read, Update, Delete.
Dispose d’un ensemble de méthodes permettant d’accéder à la base en
lecture et en écriture:
Open() : Ouvrir la base de données en lecture ou en écriture
Query() : Pour exécuter des requêtes SQL
Update () : Mettre à jour la base de données
Close() : Fermer une connexion à la base de données.
En addition elle propose execSQL permettant d’exécuter des requêtes SQL
natives.
SQLiteDatabase :
Accéder à la base :
Ouvrerture en écriture
SQLiteDatabase db = db.getWritableDatabase();
Ouvrerture en lecture
SQLiteDatabase db = db.getReadableDatabase();
SQLite
Ajouter un nouvel objet dans la base de données
Utiliser les requêtes natives SQL
Utiliser les méthodes génériques de la classe SQLDatabase
SQLite
Méthodes génériques : insert : exemple
ContentValues values = new ContentValues();
values.put(CODE, 10);
values.put(NOM, ”Ahmed”);
values.put(MOYENNE, 12.5f);
return Bdd.insert(TETUDIANTS,null,values);
Méthodes génériques : insert
ContentValues : Classe de type HashMap
permettant de passer les valeurs à insérer dans
la base de données aux méthodes génériques
Les clefs sont les noms des colonnes des tables
telles qu’elles ont été nommées à la création de
la table
Les valeurs sont les valeurs à insérer pour
chaque colonne
Requêtes natives SQL
myBase.execSQL("insert into categorie values (" +
c.nom + ", " + c.description + "");
myBase.execSQL("insert into categorie values
( ?, ?", new String[] {c.nom, c.description});
myBase.execSQL("delete from categorie where id=” +
10);
myBase.execSQL("delete from categorie where id=?",
new Integer[] {10});
Curseur :
Un curseur est une classe permettant d’exposer les
réponses d’une requête SQLite en Android.
Les curseurs peuvent être considérés comme des
ResultSet
Utilisés dans les requêtes de lecture sur la base
Cursor est une classe dérivée de SQLCursor exposant
les méthodes permettant de manipuler plus
simplement les curseurs.
Curseur : parcourir un curseur
Cursor cursor = myBase.query("categorie", null, null, null, null,
null, null);
cursor.moveToFirst();
while (cursor.isAfterLast() == false)
{
nom = cursor.getString(cursor.getColumnIndex("nom"));
description =
cursor.getString(cursor.getColumnIndex("description"));
cursor.moveToNext()}
NB : Ouverture explicite.
Curseur : Opérations sur le curseur
Obtenir le nombre de lignes dans un curseur :
cursor.getCount();
Obtenir le nombre de colonnes :
cursor.getColumnCount();
Se déplacer dans un curseur :
cursor.move(-1); //remonter d’un niveau
cursor.move(2); //Descendre de deux niveaux
Fermer le cursor :
cursor.close();
NB : Il faut fermer un curseur après utilisation.
Bonnes pratiques
Utiliser une classe statique dans laquelle vous déclarerez le nom de
la base de données, des tables ainsi que les colonnes des tables.
N’oubliez jamais de fermer la base de données après chaque
utilisation
Toujours fermer les curseurs
Vérifiez toujours qu’un curseur a au moins une ligne avant de le
parcourir.
Evitez d’accéder à la base de données dans le thread principal de
l’application.
Bonnes pratiques
Évitez donc de mettre des volumes de données importants
dans vos bases ou d’effectuer des requêtes fréquentes
De structures simples résultent des requêtes simples et des
données facilement identifiables.
SQLite étant une base de données légère, vous devrez éviter
d’y enregistrer des données binaires (images, par exemple). À
la place, créez des fichiers sur le support de stockage et
faites-y référence dans la base (Puisque vous pourriez avoir
exposer ces données binaires à d’autres applications)
Ajouter systématique une colonne d’index auto-incrémentable
de façon à présenter chaque ligne de façon unique.
Démarche (voir TD/TP)
I) Créez la classe MySQLiteHelper qui se charge de la création
et de la mise à jour de la BDD (OnCreate() et onUpgrade). Elle
définit également plusieurs constantes pour le nom et les
colonnes de la table
private static final String DATABASE_NAME = "Etudiants.db";
private static final String DATABASE_VERSION = 1;
private static final int DATABASE_CREATE = = "create table "
+ DATABASE_NAME + "(" + COLUMN_ID + " integer primary
key autoincrement, " + COLUMN_NOM + " text not null).
Démarche (voir TD/TP)
II) Pour chaque table de votre base, créez une classe Java pour
définir chaque enregistrement.
Attributs = champs de la table
Méthodes Constructeurs , Getters, Setters…etc.
III) Pour chaque table, créez une classe Java pour gérer l’accès
aux données.
Overture, fermeture, Insertion, mise à jour, suppression …
etc.
Et les requêtes.
Cursor cursor = database.query("SELECT * from student where
name = ? and age > ?",new String[]{"Ahmed","20"});
void execSQL (String sql)
Execute a single SQL statement that is NOT a SELECT or any other SQL statement that returns
data.
void execSQL (String sql, Object[] bindArgs)
Execute a single SQL statement that is NOT a SELECT/INSERT/UPDATE/DELETE.
rawQuery(String sql, String[] selectionArgs)Runs the provided SQL and
returns a Cursor over the result set.
Cursor uery(String
table, String[] columns, String selection, String[]selectionArgs
, String groupBy, String having, String orderBy, String limit)
Query the given table, returning a Cursor over the result set