Fil RSS

[Android #3] Gestion d’une base de données Android

5

janvier 25, 2012 par Arctarus, 9 157 vues

Comme c’était prévu depuis un moment, je m’attelle donc à la tâche de réaliser un nouveau tuto sur Android. Dans ce billet, je vais vous présenter une méthode d’implémentation d’une base de données sous Android, base de données au format SQLite.

Au niveau de la liste des tutos sur Android qui sont présents sur le site, voici où nous en sommes (les autres viendront bientôt) :

Donc comme je le disais, je vais m’attarder ici sur la création d’une base de données, et son utilisation depuis une application basique. Pour cela, on reprend le projet du premier tuto, le HelloWorld, et on va y insérer tout ce qui faut. Pour rappel, l’organisation de ce petit projet est la suivante :

android archi project [Android #3] Gestion dune base de données Android

Création de la base de données

La base de données en elle-même va être très simple puisqu’elle ne va être constituée que d’une seule table. Celle table contiendra des informations préchargées et elle contiendra simplement un identifiant, un nom et un prénom. Pour créer la base, vous allez donc devoir créer une nouvelle classe java. Pour l’exemple, je la nomme DBHelper.java. Cette classe doit également héritée de SQLiteOpenHelper afin de pouvoir appeler les méthodes liées à la gestion de base de données. Elle ressemble donc, avant modification à ça :

public class DBHelper extends SQLiteOpenHelper {
	private static final String TAG = "DBHelper";
	private static final String DATABASE_NAME = "database_helloworld"; // nom que l'on souhaite donner à la base
	private static final int DATABASE_VERSION = 1; // version de la bdd, permet les mises à jour des tables et champs au lancement de l'application

	public DBHelper(Context context)
        {
             super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

	@Override
	public void onCreate(SQLiteDatabase arg0) {

	}

	@Override
	public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {

	}
}

Automatiquement, Eclipse se charge d’implémenter les méthodes onCreate et onUpgrade, vous devez cependant implémenter le constructeur manuellement.

Maintenant que la classe gérant la base de données est en place, on va y ajouter ce qui va permettre la création de la table et les champs correspondant. Pour cela, je modifie la classe pour que ça donne la chose suivante :

public class DBHelper extends SQLiteOpenHelper {
	private static final String TAG = "DBHelper";
	private static final String DATABASE_NAME = "database_helloworld";
	private static final int DATABASE_VERSION = 1;

	public static final String DATABASE_TABLE_USER = "USER";

	// Table: USER
	private static final String DATABASE_CREATE_USER =
		"CREATE TABLE " +  DATABASE_TABLE_USER + " (" +
		"USR_ID INTEGER PRIMARY KEY, " +
		"USR_NAME TEXT NOT NULL, " +
		"USR_LASTNAME TEXT NOT NULL);";

        private static final String DATABASE_INSERT_USER =
		"INSERT INTO " + DATABASE_TABLE_USER + "(USR_NAME, USR_LASTNAME) " +
		"VALUES ('Arctarus', 'TrollMe');"; 

        public DBHelper(Context context)
        {
                super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL(DATABASE_CREATE_USER);
                db.execSQL(DATABASE_INSERT_USER);
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		Log.w(TAG, "UPGRADING DATABASE FROM VERSION " + oldVersion
	              + " TO "
	              + newVersion + ", WHICH WILL DESTROY ALL OLD DATA !");

                db.execSQL("DROP TABLE IF EXISTS " + DATABASE_CREATE_USER);
	}

}

J’ai donc rajouté ici plusieurs choses :

  • Une variable statique DATABASE_TABLE_USER qui permet de définir un nom à la table. L’utilité de mettre cela en variable est lors des mises à jour et des modifications possibles apportées aux noms de table, ou lorsque vous aurez à faire des requêtes par la suite.
  • Une variable statique DATABASE_CREATE_USER qui permet de définir la structure de la table à créer. Là aussi, mettre ça dans une variable permet d’avoir un seul endroit à modifier si la structure change.
  • Une variable statique DATABASE_INSERT_USER qui permet l’ajout d’un utilisateur par défaut dans la table. Bien entendu, cette variable pourra par la suite être supprimée si vous ne souhaitez pas renseigner d’informations par défaut dans votre base de données.
  • Lors de la création de la base de données, la classe va se charger de manière automatique de créer la table utilisateur qui nous intéresse via la méthode onCreate, ainsi qu’un utilisateur par défaut.
  • Lors d’une mise à jour de version de la base de données, la méthode onUpgrade est appelée et va se charger de supprimer tous les enregistrements des tables avant une mise à jour de leurs structures.

Nous avons donc maintenant la base de données correctement définie et créée, il ne reste plus qu’à s’en servir.

Utilisation de la base de données

Afin de m’y retrouver plus facilement, et ne pas réécrire 50 fois les mêmes requêtes, je vais créer une nouvelle classe qui va implémenter toutes les méthodes servant à utiliser la base de données (requêtes Select, Insert, Update, ouverture et fermeture de la base de données). Cette nouvelle classe va être nommée DBAdapter.java et va se présenter comme suit :

public class DBAdapter {
    private static final String TAG = "DBAdapter";
    private final Context context;
    private DBHelper databaseHelper;
    private SQLiteDatabase db;

    public DBAdapter(Context ctx)
    {
        this.context = ctx;
        databaseHelper = new DBHelper(context);
    }

    //Open the database
    public DBAdapter open() throws SQLException
    {
        db = databaseHelper.getWritableDatabase();
        return this;
    }

    //Close the database
    public void close()
    {
    	databaseHelper.close();
    }

    public Cursor ExecuteQuery(String Query, String[] selectionArgs)
    {
    	Cursor mCursor = null;

    	// Open Android Database
    	db = databaseHelper.getWritableDatabase();

    	mCursor = db.rawQuery(Query, selectionArgs);

    	if (mCursor != null) {
            mCursor.moveToFirst();
        }

	// Close Android Database
    	databaseHelper.close();

    	return mCursor;
    }
}

Là aussi, quelques explications s’imposent.

  • Le constructeur permet simplement d’indiquer quelle base de données nous allons utiliser pour l’application.
  • La méthode open(), comme son nom l’indique, permet d’indiquer au système que nous souhaitons ouvrir une connexion à la base de données.
  • A l’inverse, la méthode close() permet de fermer la connexion à la base de données.
  • Enfin, la méthode ExecuteQuery() permet tout simplement d’exécuter n’importe quelle requête SELECT sur la base de données. Celle-ci renvoie un objet Cursor, qui correspond au Dataset/Datareader en .NET.

Il ne reste plus qu’à ajouter autant de méthodes que voulu pour gérer notre base de données. Pour l’exemple, j’ajoute une méthode qui va se charger d’ajouter un utilisateur à la table correspondante. Cette méthode prend en paramètre deux String, correspondant au prénom et nom de l’utilisateur que l’on veut ajouter dans la table. Si l’insertion s’est bien déroulée, elle renvoie l’identifiant de l’enregistrement inséré, dans le cas contraire zéro.

    public long insertUser(String name, String lastname)
    {
    	long idUser = 0;

    	try
    	{
	    	// Open Android Database
	    	db = databaseHelper.getWritableDatabase();

	    	ContentValues initialValues = new ContentValues();
	    	initialValues.put("USR_NAME", name);
	    	initialValues.put("USR_LASTNAME", lastname);
	    	idUser = db.insert(DBHelper.DATABASE_TABLE_USER, null, initialValues);
    	}
    	catch  (SQLException sqle)
    	{
    		Log.e(TAG, "insertUser Error");
    		Log.e(TAG, "Exception : " + sqle);
    	}
    	finally
    	{
    		// Close Android Database
    		databaseHelper.close();
    	}

    	return idUser;
    }

Enfin, on ajoute la méthode qui va permettre de sélectionner les informations d’un utilisateur en passant en paramètre son identifiant :

public Cursor selectUser(int userId)
{
    	String Query = "SELECT USR_ID, USR_NAME, USR_LASTNAME" +
				" FROM " + DBHelper.DATABASE_TABLE_USER +
				" WHERE USR_ID = " + userId;

    	Cursor mCursor = ExecuteQuery(Query, null);

    	return mCursor;
}

La partie back-end est maintenant terminée, il ne reste donc plus qu’à faire les appels à cette classe depuis l’activité de notre application, histoire de vérifier qu’elle a le comportement souhaitée.

Du coté de l’Activité

Pour tester tout ça du coté de l’application, on va modifier le layout de l’activité HelloWorldActivity.java (main.xml) afin d’afficher les informations dans des contrôles. Ainsi, on va avoir deux EditView et un Button qui permettront de voir que notre base de données fonctionne correctement.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >

	<EditText
	    android:id="@+id/username"  
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content"/>

	<EditText
            android:id="@+id/lastname"  
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content"/>

       <Button
	    android:id="@+id/adduser"  
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content"
	    android:text="@string/add_user"/>
</LinearLayout>

Et au niveau du code java de l’activité, on modifie le code pour aller chercher les informations en base de données. Ci-après, l’Activité comme est doit être.

public class HelloWorldActivity extends Activity {
    private EditText evName;
    private EditText evLastname;
    private Button addUser;

    private String name;
    private String lastname;

    private DBAdapter db;
    private Cursor userCursor;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // Récupération des contrôles
        evName = (EditText) findViewById(R.id.username);
        evLastname = (EditText) findViewById(R.id.lastname);

        db = new DBAdapter(getApplicationContext());
        // Sélectionne l'utilisateur par défaut
        userCursor = db.selectUser(1); 
        if(userCursor != null && userCursor.getCount() != 0)
        {
        	evName.setText(userCursor.getString(userCursor.getColumnIndex("USR_NAME")));
        	evLastname.setText(userCursor.getString(userCursor.getColumnIndex("USR_LASTNAME")));

        	userCursor.close();
        }

        addUser = (Button)findViewById(R.id.adduser);
        addUser.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				// Récupération des informations renseignées par l'utilisateur
				name = evName.getText().toString();
				lastname = evLastname.getText().toString();

				long lastUser = db.insertUser(name, lastname);
				if(lastUser != 0)
				{
					userCursor = db.selectUser(lastUser); 
			        if(userCursor != null && userCursor.getCount() != 0)
			        {
			        	// Affichage des informations de l'utilisateur inséré
			        	evName.setText(userCursor.getString(userCursor.getColumnIndex("USR_NAME")));
			        	evLastname.setText(userCursor.getString(userCursor.getColumnIndex("USR_LASTNAME")));

			        	userCursor.close();
			        }
				}
			}
		});
    }
}

Vous n’avez plus qu’à lancer l’application et tester le bon fonctionnement. Lors du lancement, les champs devraient être remplis avec les valeurs insérées par défaut (dans mon cas, Arctarus et TrollMe). Et lors du clic sur le bouton, les champs devraient se mettre à jour avec les valeurs que vous avez renseignés.

Conclusion

Voilà, nous arrivons au terme de ce billet. Comme vous pouvez le voir, l’implémentation et l’utilisation d’une base de données n’est pas très compliquée en soit. Il faut juste prendre le temps de savoir où on veut aller. Après, le plus long sera seulement de créer les méthodes qui vont bien avec nos besoins et de les utiliser.

Pour aller plus loin sur le sujet, je vous invite à aller vous documenter sur la documentation de SQLite3. Ceci va vous permettre de voir comment sont gérés les différents types de données au sein de la base de données, ainsi que les différentes erreurs que vous pourriez rencontrer.

En attendant, j’espère que ce nouveau tuto vous convient. Je reste bien entendu à votre écoute, toutes vos remarques, questions, suggestions sont les bienvenues pour améliorer ce billet (ou les autres).


5 commentaires »

  1. hayet dit :

    svp qui peut m’aider à resoudre ce probléme,j’ai cré une base des données local SQLite sur android avec XML mais mon proléme c’est je que veux céer plusieurs tables dans la meme base sachant que chaque table a son propre XML

  2. Arctarus dit :

    Bonjour,

    Je ne connais pas la définition des bases de données par XML mais peux-tu montrer les fichiers qui te servent pour gérer ta base de données stp ?

    Avec ces fichiers, ce sera surement plus facile de te filer un coup de main sur ton problème.

  3. lol dit :

    C’est super mal expliquer, un tuto fait à l’arrache… que de temps perdu…

  4. Anteus dit :

    Merci pour ce tuto.

    Bien qu’il n’exclut pas de « mutualiser » les différentes sources d’information, il apporte un éclairage intéressant sur le code du layout et de l’activité, une fois la base mise en place.

  5. Bradley dit :

    gooooooooooooooood djobbbb

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>