sio2:gestion_des_donnees_avec_sqlite

Les articles saisis devront être mémorisés dans une base de données SQLite sous Android.

a. Généralités

SQLite est un système de gestion de base de données compatible SQL léger et embarqué, qui ne requiert pas de serveur externe. Tout est inclus dans une seule bibliothèque (d'où la caractéristique “embarqué” avec l'application), ce qui facilite son intégration dans une large variété d’applications. Son architecture légère la rend adaptée aux environnements avec des ressources limitées, comme les appareils mobiles et les systèmes embarqués.

Par ailleurs, SQLite garantit la conformité aux propriétés ACID : Atomicité, Cohérence, Isolation, Durabilité. Ceci assure la fiabilité des opérations de base de données, même en cas d’interruption soudaine du système.

SQLite est disponible sur n'importe quel terminal sous Android. Utiliser une base SQLite ne requiert aucune étape d'administration ou de paramétrage préalable. Il suffit simplement d'écrire les requêtes SQL permettant de créer ou de mettre à jour la base de données. Celle ci est ensuite gérée automatiquement par la plateforme Android.

Accéder à une base de données SQLite implique d'accéder à un fichier stocké dans le répertoire /data/data/nomDuPackage/databases. Cette opération peut être plus ou moins longue. Il est donc recommandé de réaliser toutes les opérations sur la base de données de manière asynchrone, par exemple via la classe AsyncTask de l'API Android. Ce que nous ne ferons pas ici pour des raisons de simplification.

b. Utilisation de SQLite

Le sous package android.database.sqlite contient les classes spécifiques à SQLite.

La classe SQLiteDatabase

La classe SQLiteDatabase est la classe principale permettant de travailler avec les bases de données SQLite. Elle offre plusieurs méthodes pour accéder à la base de données, exécuter des requêtes de sélection ou de mise à jour et fermer la base de données :

  • insert() : méthode pour insérer des donnése dans une table
  • execSQL() : exécuter une requête SQL qui ne retourne pas de réponses
  • query() : retourne un Cursor de données en fonction de paramètres fournis
  • rawQuery() : retourne un Cursor en prenant en entrée directement une requête SQL
  • update() : méthode pour mettre à jour un ensemble de données
  • delete() : méthode pour supprimer un ensemble de données

Les méthodes insert() et update() utilisent en paramètre la classe ContentValues qui décrit sous forme de clé / valeur la donnée à insérer en base. Cette classe fonctionne comme la classe HashMap (Dictionnaire).

L'Objet Cursor

Les méthodes query() et rawQuery() retournent un objet de type Cursor. Cet objet représente le résultat de la requête exécutée et pointe généralement sur un élément de la liste du résultat. Ce principe permet d'éviter de devoir tout charger en mémoire.

La classe Cursor offre les méthodes nécessaires pour naviguer dans la liste des éléments du résultat de la requête, en voici quelques unes :

  • getCount() : retourne le nombre d'éléments du résultat de la requête
  • move() : méthodes permettant de déplacer le curseur dans le résultat
  • isAfterLast() : permet de déterminer si on a atteint la fin de la liste du résultat
  • get…(int columnIndex) : ensemble de méthodes permettant de retourner la valeur typée d'une colonne donnée selon son index. Exemple : getLong() ou getString()
  • getColumnIndex() : retourne l'index correspondant au nom de la colonne ou retourne -1 si le nom de la colonne n'existe pas
  • getColumnIndexOrThrow(String columnName) : retourne l'index correspondant au nom de la colonne ou lève une exception si le nom de la colonne n'existe pas

Pour plus d'informations, cf https://developer.android.com/reference/android/database/Cursor

Les types de données gérés

  • SQLite supporte les types suivants :
  • NULL : valeur non définie
  • TEXT : équivalent à String en Java
  • INTEGER : équivalent à int en Java
  • REAL : équivalent à double en Java
  • BLOB : la donnée est enregistrée comme elle a été donnée

a. Création de la couche métier

  • Dans app/src/main/java, créer un nouveau package nommé metier (Clic droit sur app/java)
  • Dans ce package, créer la classe Java nommée Article. Cette classe nous servira de passerelle vers la base de données.
    • La classe Article comprendra les attributs id(int initialisé à 0), reference(String), designation(String), prix(float) et qte(int).
    • Elle devra disposer des accesseurs (getters), de la méthode toString() et de 2 constructeurs (clic droit puis Generate) :
      • l'un avec tous les attributs
      • l'autre sans l'attribut id.

b. Création de la base de données, classe CreateBdInventaire

  • Toujours dans app/src/main/java créer un nouveau package nommé bdd
  • Dans ce package, créer la classe Java CreateBdInventaire. Cette classe hérite de la classe SQLiteOpenHelper. Elle permet de définir la structure de la base de données.
    • Renseigner la superclass
    • Redéfinir les méthodes onCreate et onUpdate
    • Générer automatiquement le constructeur, faites-le en utilisant la première proposition :

  • Lors de l'instanciation de cette classe, le système vérifiera si la base existe :
    • si elle n'existe pas, il la créera en faisant appel à la méthode onCreate
    • si elle existe, il vérifie la version, si la version de la base a changé, la base sera regénérée, (méthode onUpgrade).
  • Code de la classe CreateBdInventaire :
public class CreateBdInventaire extends SQLiteOpenHelper { 
   public static final String TABLE_ARTICLE = "article"; 
   private static final String CREATE_TABLE_ARTICLE = 
    "CREATE TABLE " + TABLE_ARTICLE + "(" + 
    "id INTEGER PRIMARY KEY AUTOINCREMENT, " + 
    "ref TEXT NOT NULL, " + 
    "des TEXT NOT NULL, " + 
    "pu REAL," + 
    "qte INTEGER);"; 
  
  // Constructeur, à générer automatiquement 
  public CreateBdInventaire(@Nullable Context context, @Nullable String name,  @Nullable SQLiteDatabase.CursorFactory factory, int version) { 
    super(context, name, factory, version); 
  } 
 
  /** 
  * Création de la base de données si elle n'existe pas 
  * @param db base 
  */ 
  @Override 
  public void onCreate(SQLiteDatabase db) { 
    db.execSQL(CREATE_TABLE_ARTICLE); 
    Log.d("bdd", "Base créée"); 
  } 
  
  /** 
  * Création d'une nouvelle base en cas de changement de version  
  * @param db 
  * @param oldVersion 
  * @param newVersion 
  */ 
  @Override 
  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  db.execSQL("DROP TABLE " + TABLE_ARTICLE + ";"); 
     Log.d("bdd", "Table " + TABLE_ARTICLE + " supprimée"); 
     onCreate(db); 
  } 
 } 

NB Les instructions Log.d permettent de pister le déroulement du programme. (d = debug)

c. Création de la classe gérant les accès à la base de données : DAO

Dans le package bdd, nous allons ajouter une nouvelle classe DAO (Data Access Object) chargée de gérer l'accès à la base de données. Cette classe disposera

  • des attributs suivants :
private static final int VERSION_BDD = 1; 
private static final String NOM_BDD = "inventaire.db"; 
private CreateBdInventaire createBD = null; 
private SQLiteDatabase db = null; 
  • d'un constructeur :
  • d'une méthode open pour ouvrir la base de données :
  • et d'une méthode close pour la fermer :

d. Création de la classe gérant les accès à la table article : Article DAO

Enfin, dans le package bdd, nous allons ajouter la classe ArticleDAO chargée de gérer les accès à la table article (méthodes CRUD).

Cette classe disposera d'abord d'un constructeur et d'une méthode permettant de fermer la base de données :

Puis des méthodes CRUD, notamment la méthode create(Article unArticle), chargée de créer l'article passé en paramètre dans la base de données. Les autres méthodes d'accès à la base seront insérées par la suite.

e. Insertion des données saisies

Modification de la classe AjoutArticleActivity : jusqu'à présent seul le bouton Quitter était géré, il faut désormais gérer le bouton Ajout.

  • 1) Ajouter des propriétés à cette classe :
    • a. Déclarer la variable d'accès à la table article : private ArticleDAO articleDAO = null;
    • b. Déclarer un objet de type Article : Article art = null;
    • c. Déclarer les différents contrôles graphiques :
// Contrôles graphiques 
private EditText etRef; 
private EditText etDes; 
private EditText etPrix; 
private EditText etQte; 
private Button btAjout; 
  • d. Déclarer les zones de réception des saisies
// Valeurs saisies 
String ref; 
String des; 
String prix; 
double prixN; 
String qte; 
int qteN; 
Article art; 
long idArticleCree; 
ArticleDAO artDAO;
  • 2) À la fin de la méthode onCreate, appeler la méthode creationArticle que l'on va écrire.
  • 3) Ajouter la méthode creationArticle()
private void creationArticle() {
  // Reconnaissance des contrôles graphiques de la vue
  etRef = (EditText) findViewById(R.id.etRef);
  etDes = (EditText) findViewById(R.id.etdesign);
  etPrix = (EditText) findViewById(R.id.etPrix);
  etQte = (EditText) findViewById(R.id.etQte);
  btAjout = (Button) findViewById(R.id.btAjouter);
  
  // Accès à la table article
  articleDAO = new ArticleDAO(this);
  
  // Gestion de l'événement onClick sur le boutn Ajouter
  btAjout.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View arg0) {
    // Récupération des zones saisies
     ref = etRef.getText().toString();
     des = etDes.getText().toString();
     prix = etPrix.getText().toString();
     prixN = Float.valueOf(prix);
     qte = etQte.getText().toString();
     qteN = Integer.valueOf(qte);
     // Création de l'article correspondant
     art = new Article(ref, des, prixN, qteN);
     // Insertion de l'article dans la base de données
     long idArticleCree = articleDAO.create(art);
     // Message à l'écran
     Toast.makeText(getApplicationContext(), "Produit ajouté + " +
     "(no : " + idArticleCree + " )",Toast.LENGTH_SHORT).show();
     // Zones de saisies effacées
     etRef.setText("");
     etRef.requestFocus();
     etDes.setText("");
     etPrix.setText("");
     etQte.setText("");
    }
   });
}
  • 4) Fermer la base de données quand l'utilisateur quitte la fonctionnalité, ajouter : artDAO.close(); avant finish();
  • 5) Tester : Ajouter des articles. Le message indiquant le numéro de l'article ajouté doit s'afficher.

Montrer l'application à Mme Thevenot

a. Vérifier les entrées du Logcat

Après le lancement de l'application, sélectionner l'onglet Logcat en bas de l'écran au niveau de la partie Android Monitor. Si cet onglet n'est pas présent, lier le debugger au process, icone (Attach debugger to Android process), cocher show all processes, puis sélectionner l'application Inventaire.

À droite de la liste des onglets, dans le filtre indiquer : bdd afin de sélectionner les messages de debug (log.d) dont le nom est bdd

Créer un article, l'affichage suivant devrait apparaitre :

b. Utilisation de Database Inspector (avec un périphérique Android )

Cf https://developer.android.com/studio/inspect/database

Remarque : l'outil d'inspection de bases de données fonctionne uniquement avec la bibliothèque SQLite incluse dans le système d'exploitation Android à partir du niveau d'API 26.

Répondre aux questions suivantes à la suite du document déposé sur le Drive.

  1. Présenter brièvement le travail à effectuer
  2. Citer les 3 classes permettant la gestion de la base de données, et préciser le rôle de chacune
  3. Quand la base de données est-elle créée ?
  4. Tester le changement de version et copier l'affichage de la console Logcat correspondant
  5. En effectuant quelques recherches sur Internet, présentez les caractéristiques d'une base de données SQLite implémentée sur un smartphone.
  6. Expliquer comment procéder pour ajouter la table categorie(id, libelle) à la base de données et la relier à la table article (clé étrangère idCategorie).

Montrer le document à Mme Thevenot

  • sio2/gestion_des_donnees_avec_sqlite.txt
  • Dernière modification : 2024/12/02 09:47
  • de dthevenot