Utilisation d'une base SQLite sous Android

Par Jean-François GAZET le 25 janvier 2015

SQLite est un moteur de base de données relationnel gratuit. Il est facilement portable car le moteur et les données sont contenus dans un même fichier. C’est donc un excellent choix pour le stockage de données dans un smartphone.

Vous trouverez en bas de cet article toutes les informations utiles pour créer et gérer une base SQLite sur votre ordinateur.

Pour utiliser une base SQLite dans votre application Android, je vous propose d’étudier deux cas concrets :

  • A) La base de données (vide) est créée par l’application lors de sa première utilisation;
  • B) Vous disposez déjà d’une base existante avec ses données que vous souhaitez intégrer et utiliser dans l’application.

Dans les deux cas, suivez les étapes suivantes.

I) Pour chaque table de votre base, créez une classe Java pour définir chaque enregistrement

Par exemple, vous avez une table “animal” avec les champs “id” et “nom”. On va donc créer la classe “Animal” comme suit :

public class Animal {

    private int id_animal;
    private String nom_animal;

    // Constructeur
    public Animal(int id,String nom) {
        this.id_animal=id;
        this.nom_animal=nom;
        }

    public int getId_animal() {
        return id_animal;
        }

    public void setId_animal(int id) {
        this.id_animal = id;
        }

    public String getNom_animal() {
        return nom_animal;
        }

    public void setNom_animal(String nom) {
        this.nom_animal = nom;
        }

    } // class Animal

II) Pour chaque table, créez une classe Java pour gérer l’accès aux données

On va utiliser une classe pour se connecter à la table “Animal” et pouvoir ainsi lire, écrire et supprimer des données :

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

public class AnimalManager {

    private static final String TABLE_NAME = "animal";
    public static final String KEY_ID_ANIMAL="id_animal";
    public static final String KEY_NOM_ANIMAL="nom_animal";
    public static final String CREATE_TABLE_ANIMAL = "CREATE TABLE "+TABLE_NAME+
        " (" +
        " "+KEY_ID_ANIMAL+" INTEGER primary key," +
        " "+KEY_NOM_ANIMAL+" TEXT" +
        ");";
    private MySQLite maBaseSQLite; // notre gestionnaire du fichier SQLite
    private SQLiteDatabase db;

    // Constructeur
    public AnimalManager(Context context)
        {
        maBaseSQLite = MySQLite.getInstance(context);
        }

    public void open()
        {
        //on ouvre la table en lecture/écriture
        db = maBaseSQLite.getWritableDatabase();
        }

    public void close()
        {
        //on ferme l'accès à la BDD
        db.close();
        }

    public long addAnimal(Animal animal) {
        // Ajout d'un enregistrement dans la table

        ContentValues values = new ContentValues();
        values.put(KEY_NOM_ANIMAL, animal.getNom_animal());

        // insert() retourne l'id du nouvel enregistrement inséré, ou -1 en cas d'erreur
        return db.insert(TABLE_NAME,null,values);
        }

    public int modAnimal(Animal animal) {
        // modification d'un enregistrement
        // valeur de retour : (int) nombre de lignes affectées par la requête

        ContentValues values = new ContentValues();
        values.put(KEY_NOM_ANIMAL, animal.getNom_animal());

        String where = KEY_ID_ANIMAL+" = ?";
        String[] whereArgs = {animal.getId_animal()+""};

        return db.update(TABLE_NAME, values, where, whereArgs);
        }

    public int supAnimal(Animal animal) {
        // suppression d'un enregistrement
        // valeur de retour : (int) nombre de lignes affectées par la clause WHERE, 0 sinon

        String where = KEY_ID_ANIMAL+" = ?";
        String[] whereArgs = {animal.getId_animal()+""};

        return db.delete(TABLE_NAME, where, whereArgs);
        }

    public Animal getAnimal(int id) {
        // Retourne l'animal dont l'id est passé en paramètre

        Animal a=new Animal(0,"");

        Cursor c = db.rawQuery("SELECT * FROM "+TABLE_NAME+" WHERE "+KEY_ID_ANIMAL+"="+id, null);
        if (c.moveToFirst()) {
            a.setId_animal(c.getInt(c.getColumnIndex(KEY_ID_ANIMAL)));
            a.setNom_animal(c.getString(c.getColumnIndex(KEY_NOM_ANIMAL)));
            c.close();
            }

        return a;
        }

    public Cursor getAnimaux() {
        // sélection de tous les enregistrements de la table
        return db.rawQuery("SELECT * FROM "+TABLE_NAME, null);
        }

    } // class AnimalManager

III) Gestion de la base SQLite

Pour gérer le fichier SQLite, on va créer une classe qui hérite de SQLiteOpenHelper. Celle-ci inclut, entre autres, les méthodes suivantes :

  • onCreate() : code exécuté à la création du fichier SQLite;
  • onUpgrade() : code exécuté lors de la mise à jour du schéma relationnel de votre base de données.

On ajoute les constantes suivantes :

  • DATABASE_NAME : choisissez un nom de fichier pour votre base de données;
  • DATABASE_VERSION : numéro de version de la base de données. Mettez 1 pour commencer. A chaque évolution de la structure de votre base, incrémentez manuellement ce nombre.

Revenons à nos 2 cas cités en introduction.

A) Vous créez une base vierge au premier lancement de l’application : utilisez la classe MySQLite() ci-dessous.

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class MySQLite extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "db.sqlite";
    private static final int DATABASE_VERSION = 1;
    private static MySQLite sInstance;
    
    public static synchronized MySQLite getInstance(Context context) {
        if (sInstance == null) { sInstance = new MySQLite(context); }
        return sInstance;
        }    

    private MySQLite(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        // Création de la base de données
        // on exécute ici les requêtes de création des tables
        sqLiteDatabase.execSQL(AnimalManager.CREATE_TABLE_ANIMAL); // création table "animal"
        }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i2) {
        // Mise à jour de la base de données
        // méthode appelée sur incrémentation de DATABASE_VERSION
        // on peut faire ce qu'on veut ici, comme recréer la base :
        onCreate(sqLiteDatabase);
        }

    } // class MySQLite

B) Vous utilisez une base existante.

  • placez le fichier SQLite dans le dossier app/src/main/assets
  • utilisez la classe MySQLite() ci-dessous.
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

class MySQLite extends SQLiteOpenHelper {

    private final Context mycontext;
    private static MySQLite sInstance;

    private static final int DATABASE_VERSION = 1; // l'incrément appelle onUpgrade(), décrément => onDowngrade()
    private String DATABASE_PATH; // chemin défini dans le constructeur
    private static final String DATABASE_NAME = "db.sqlite";
    
    public static synchronized MySQLite getInstance(Context context) {
        if (sInstance == null) { sInstance = new MySQLite(context); }
        return sInstance;
        }    

    // Constructeur
    private MySQLite(Context context) {

        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        this.mycontext=context;
        String filesDir = context.getFilesDir().getPath(); // /data/data/com.package.nom/files/
        DATABASE_PATH = filesDir.substring(0, filesDir.lastIndexOf("/")) + "/databases/"; // /data/data/com.package.nom/databases/

        // Si la bdd n'existe pas dans le dossier de l'app
        if (!checkdatabase()) {
            // copy db de 'assets' vers DATABASE_PATH
            copydatabase();
            }
        }

    private boolean checkdatabase() {
        // retourne true/false si la bdd existe dans le dossier de l'app
        File dbfile = new File(DATABASE_PATH + DATABASE_NAME);
        return dbfile.exists();
        }

    // On copie la base de "assets" vers "/data/data/com.package.nom/databases"
    // ceci est fait au premier lancement de l'application
    private void copydatabase() {

        final String outFileName = DATABASE_PATH + DATABASE_NAME;

        InputStream myInput;
        try {
            // Ouvre la bdd de 'assets' en lecture
            myInput = mycontext.getAssets().open(DATABASE_NAME);

            // dossier de destination
            File pathFile = new File(DATABASE_PATH);
            if(!pathFile.exists()) {
                if(!pathFile.mkdirs()) {
                    Toast.makeText(mycontext, "Erreur : copydatabase(), pathFile.mkdirs()", Toast.LENGTH_SHORT).show();
                    return;
                    }
                }

            // Ouverture en écriture du fichier bdd de destination
            OutputStream myOutput = new FileOutputStream(outFileName);

            // transfert de inputfile vers outputfile
            byte[] buffer = new byte[1024];
            int length;
            while ((length = myInput.read(buffer)) > 0) {
                myOutput.write(buffer, 0, length);
                }

            // Fermeture
            myOutput.flush();
            myOutput.close();
            myInput.close();
            }
        catch (IOException e) {
            e.printStackTrace();
            Toast.makeText(mycontext, "Erreur : copydatabase()", Toast.LENGTH_SHORT).show();
            }
            
        // on greffe le numéro de version
        try{
            SQLiteDatabase checkdb = SQLiteDatabase.openDatabase(DATABASE_PATH + DATABASE_NAME, null, SQLiteDatabase.OPEN_READWRITE);
            checkdb.setVersion(DATABASE_VERSION);
            }
        catch(SQLiteException e) {
            // bdd n'existe pas
            }
                        
        } // copydatabase()

    @Override
    public void onCreate(SQLiteDatabase db) {}

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        if (oldVersion < newVersion){
            //Log.d("debug", "onUpgrade() : oldVersion=" + oldVersion + ",newVersion=" + newVersion);
            mycontext.deleteDatabase(DATABASE_NAME);
            copydatabase();
            }    
        } // onUpgrade
        
    } // class MySQLite

Voici un schéma des classes Java que nous venons de créer : exemple-sqlite

Vous pouvez maintenant manipuler vos données comme ceci :

AnimalManager m = new AnimalManager(this); // gestionnaire de la table "animal"
m.open(); // ouverture de la table en lecture/écriture

// insertion. L'id sera attribué automatiquement par incrément
m.addAnimal(new Animal(0,"maya"));

// modification du nom de l'animal dont l'id est 1
Animal a=m.getAnimal(1);
a.setNom_animal("toto");
m.modAnimal(a);

// suppression
m.supAnimal(a);

// Listing des enregistrements de la table
Cursor c = m.getAnimaux();
if (c.moveToFirst())
    {
    do {
        Log.d("test",
            c.getInt(c.getColumnIndex(AnimalManager.KEY_ID_ANIMAL)) + "," +
            c.getString(c.getColumnIndex(AnimalManager.KEY_NOM_ANIMAL))
            );
        }
    while (c.moveToNext());
    }
c.close(); // fermeture du curseur

// fermeture du gestionnaire
m.close();

Informations utiles

Site officiel SQLite http://www.sqlite.org/

Logiciels gratuits de gestion d’une base SQLite

Créer une base SQLite en ligne de commande

sqlite3 nom_fichier

Alléger la taille d’un fichier SQLite
La commande SQL est VACUUM. Dans une console vous pouvez taper :

sqlite3 nom_fichier "VACUUM;"

Récupérer le fichier SQLite de l’émulateur Android
Pour copier le fichier SQLite depuis l’émulateur vers votre ordinateur, tapez la commande suivante dans une console, en remplaçant com.package.nom par le nom du paquetage de votre application :

adb pull /data/data/com.package.nom/databases/db.sqlite

Chiffrer une base SQLite
sqlcipher


Partagez cet article


A lire également Tous les articles