Tutoriel Android : Apprendre à utiliser la base de donnée SQLite

Chapitre 4.3

Android2ee

Mathias Seguy

Ce tutoriel présente l'utilisation de la base de données SQLite avec Android. Il fait partie du livre "Android a complete course" dont les chapitres sont listés ci-dessous :

- Chapitre 0 : Installation et préparation de l'environnement de développement

- Chapitre 1 : Premiers pas avec Android

- Chapitre 1.1 : Cycle de vie de l'activité

- Chapitre 2.1 : Les éléments graphiques fondamentaux

- Chapitre 2.2 : Composants graphiques complexes

- Chapitre 3.3 : Intent et IntentFilters

- Chapitre 4.1 : Les Ressources

- Chapitre 4.2 : SharedPreferences et PreferenceActivity

- Chapitre 4.3 : Base de données SQLite

- Chapitre 4.4 : Gestion des fichiers

- Chapitre 5 : Content Provider

Pour réagir à ce tutoriel, un espace de dialogue vous est proposé sur le forum : Commentez

- Titre : Tutoriel Android : Apprendre à utiliser la base de donnée SQLite

- Auteur : Mathias Seguy

- Parution : 12 décembre 2014

- Mise à jour : 24 février 2016

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2016 Mathias Seguy. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Base de données locale

- II. Ouverture et fermeture

- III. Création et mise à jour de la structure de la base

- IV. Gérer l'instanciation et l'ouverture

- V. Mise à jour des données de la table : Insert, Update et Delete de la classe SQLiteDatabase

- VI. Récupération des données de la table Query de la classe SQLiteDatabase

- VI-1. Parcourir le résultat des requêtes

- VI-2. Effectuer une requête à la main

- VI-3. Effectuer une requête avec SQLiteQueryBuilder

- VII. Gestion des transactions

- VIII. Un exemple complet

- IX. Remerciements

I - Base de données locale

La base de données installée sur Android est SQLite, par contre, elle ne se pilote pas avec le JDBC usuel, mais avec un SGBDR (Système de Gestion de Base de Données Relationnelle) spécifique. Il faut modifier nos vieilles habitudes Java d'utilisateurs d'Hibernate, d'Ibatis ou de notre bon vieux JDBC. Une grosse différence concerne le typage des données de vos colonnes qui ne sera pas utilisé par SQLite (il l'est de manière indicative uniquement) : SQLite permet de stocker une valeur de n'importe quel type dans n'importe quelle colonne, quel que soit le type déclaré de cette colonne. D'autres différences : SQLite ne reconnait pas les contraintes de clefs étrangères, les transactions imbriquées, les jointures externes, certaines variantes d'ALTER TABLE…

Cf http://www.sqlite.org/docs.html et surtout http://www.sqlite.org/lang.html pour connaître la syntaxe à utiliser.

Comment cela marche-t-il ?

La base de données est liée à votre activité (pour pouvoir partager son accès, il faut mettre en place un ContentProvider, cela sera explicité dans un autre chapitre), c'est elle qui la crée, la met à jour, la remplit,  l'interroge et la clôt. Ainsi dans le onCreate de votre activité vous appelez votre base. Si celle-ci n'existe pas, le code que vous avez implémenté pour la créer est appelé. Si sa structure a évolué, le code que vous avez écrit pour la mettre à jour est appelé. Quand vous récupérez votre base, vous la manipulez au travers d'une classe spécifique qui encapsule les appels que vous avez écrits (votre DAO). Quand vous quittez votre activité, dans la méthode Destroy, vous fermez votre base.

Dans la pratique cela implique au moins deux classes spécifiques :

- votre classe de création et de mise à jour de la base (de la structure de la base) qui étend SQLiteHelper. N'oubliez pas de mettre votre clef primaire technique unique qui s'auto-incrémente pour chacune de vos tables. Enfin, il est préconisé que tous vos noms de tables, de colonnes de la base soient des variables public final static de votre classe. Cette classe implémente au moins trois méthodes :

- le constructeur qui appelle son super (et qui prend en paramètre le numéro de version de la structure de la base),

- onCreate qui crée la base si elle n'existe pas,

- onUpdate qui met à jour votre structure de table si celle-ci a évolué. Pour savoir si elle a évolué, un numéro de version de la structure de la base est utilisé. En effet elle prend en paramètre un oldVersion et un newVersion ;

- votre classe DAO (vos classes DAO) qui encapsule vos appels à la base. Deux manières d'obtenir votre base de données sont à votre disposition :

- getWritableDatabase() pour l'obtenir en mode écriture (mais du coup évidemment c'est un mode lecture/écriture),

- getReadableDatabase() pour l'obtenir en mode lecture seule.

Enfin, souvenez-vous que vous devez utiliser les méthodes beginTransaction, endTransaction et commitTransaction si vous faites des traitements qui ne sont pas atomiques.

II - Ouverture et fermeture

1. private SQLiteDatabase db;

3. @Override

4. public void open() throws SQLiteException {

5. try {

6. db = dbHelper.getWritableDatabase();

7. } catch (SQLiteException ex) {

8. db = dbHelper.getReadableDatabase();

9. }

10. }

12. public void close() {

13. db.close();

14. }

Où la classe DBHelper est votre classe de création de la base qui étend SQLiteHelper. (cf. ci-dessous pour l'explication.)

III - Création et mise à jour de la structure de la base

Commençons par un exemple :

1. public class DBOpenHelper extends SQLiteOpenHelper {

2. /**

3. * @goals This class aims to show the constant to use for the DBOpenHelper

4. */

5. public static class Constants implements BaseColumns {

7. // The database name

8. public static final String DATABASE_NAME = "myData.db";

10. // The database version

11. public static final int DATABASE_VERSION = 1;

13. // The table Name

14. public static final String MY_TABLE = "Human";

16. // ## Column name ##

17. // My Column ID and the associated explanation for end-users

18. public static final String KEY_COL_ID = "_id";// Mandatory

20. // My Column Name and the associated explanation for end-users

21. public static final String KEY_COL_NAME = "name";

23. // My Column First Name and the associated explanation for end-users

24. public static final String KEY_COL_FIRSTNAME = "firstName";

26. // My Column Eyes Color and the associated explanation for end-users

27. public static final String KEY_COL_EYES_COLOR = "eyesColor";

29. // My Column Hair color and the associated explanation for end-users

30. public static final String KEY_COL_HAIR_COLOR = "hairColor";

32. // My Column age and the associated explanation for end-users

33. public static final String KEY_COL_AGE = "age";

35. // Indexes des colonnes

36. // The index of the column ID

37. public static final int ID_COLUMN = 1;

39. // The index of the column NAME

40. public static final int NAME_COLUMN = 2;

42. // The index of the column FIRST NAME

43. public static final int FIRSTNAME_COLUMN = 3;

45. // The index of the column EYES COLOR

46. public static final int EYES_COLOR_COLUMN = 4;

48. // The index of the column HAIR COLOR

49. public static final int HAIR_COLOR_COLUMN = 5;

51. // The index of the column AGE

52. public static final int AGE_COLUMN = 6;

53. }

55. /**

56. * The static string to create the database.

57. */

58. private static final String DATABASE_CREATE = "create table "

59. + Constants.MY_TABLE + "(" + Constants.KEY_COL_ID

60. + " integer primary key autoincrement, " + Constants.KEY_COL_AGE

61. + " INTEGER, " + Constants.KEY_COL_NAME + " TEXT, "

62. + Constants.KEY_COL_FIRSTNAME + " TEXT, "

63. + Constants.KEY_COL_EYES_COLOR + " TEXT, "

64. + Constants.KEY_COL_HAIR_COLOR + " TEXT) ";

66. /**

67. * @param context

68. *            = the context of the caller

69. * @param name

70. *            = Database's name

71. * @param factory

72. *            = null

73. * @param version

74. *            = Database's version

75. */

76. public DBOpenHelper(Context context, String name, CursorFactory factory,

77. int version) {

78. super(context, name, factory, version);

79. }

81. @Override

82. public void onCreate(SQLiteDatabase db) {

83. // Create the new database using the SQL string Database_create

84. db.execSQL(DATABASE_CREATE);

86. }

88. @Override

89. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

90. Log.w("DBOpenHelper", "Mise à jour de la version " + oldVersion

91. + " vers la version " + newVersion

92. + ", les anciennes données seront détruites ");

93. // Drop the old database

94. db.execSQL("DROP TABLE IF EXISTS " + Constants.MY_TABLE);

95. // Create the new one

96. onCreate(db);

97. // or do a smartest stuff

98. }

99. }

Qui est appelé par votre activité par :

1. dbOpenHelper = new DBOpenHelper(this, Constants.DATABASE_NAME, null,

2. Constants.DATABASE_VERSION);

Où :

·         Context est le contexte de votre activité (this quand vous êtes dans votre activité) ;

·         le nom de votre base de données ;

·         une fabrique de cureurs (le plus souvent null) ;

·         la version de la structure de votre base.

La syntaxe de création est la suivante :

Ainsi l'exemple précédent crée une table dont le nom est DATABASE_TABLE avec une colonne KEY_ID qui est la clef primaire de type entier qui s'auto-incrémente, une colonne KEY_TASK de type String, non null, et une colonne KEY_CREATION_DATE de type long.

De plus voilà la syntaxe complète de création d'une table µSQLite :

Collumn-def :

Type-name :

Column-constraint :

Table-constraint :

ForeignKey clauses :

IV - Gérer l'instanciation et l'ouverture

Pour la création et l'instanciation d'une base de données :

1. // The database.

2. private SQLiteDatabase db;

4. // The database creator and updater helper.

5. DBOpenHelper dbOpenHelper;

7. @Override

8. public void onCreate(Bundle savedInstanceState) {

9. super.onCreate(savedInstanceState);

10. setContentView(R.layout.main);

11. // Create or retrieve the database

12. dbOpenHelper = new DBOpenHelper(this, Constants.DATABASE_NAME, null,

13. Constants.DATABASE_VERSION);

14. // open the database

15. openDB();

17. // Insert a new record

18. ContentValues contentValues = new ContentValues();

19. long rowId = insertRecord(contentValues);

21. // Update that line

22. rowId = updateRecord(contentValues, rowId);

24. // Query that line

25. queryTheDatabase();

27. // And then delete it:

28. deleteRecord(rowId);

29. }

V - Mise à jour des données de la table : Insert, Update et Delete de la classe SQLiteDatabase

Pour l'insert :

1. // Crée une nouvelle ligne à insérer.

2. ContentValues newTaskValues = new ContentValues();

4. // Assign the values for each column.

5. contentValues.put(Constants.KEY_COL_NAME, "name");

6. contentValues.put(Constants.KEY_COL_FIRSTNAME, "firstName");

7. contentValues.put(Constants.KEY_COL_EYES_COLOR, "green");

8. contentValues.put(Constants.KEY_COL_HAIR_COLOR, "blond");

9. contentValues.put(Constants.KEY_COL_AGE, 6);

11. // Insert the line in the database

12. long rowId = db.insert(Constants.MY_TABLE, null, contentValues);

14. // test to see if the insertion was ok

15. if (rowId == -1) {

16. Toast.makeText(this, "Error when creating an human",

17. Toast.LENGTH_LONG).show();

18. } else {

19. Toast.makeText(this, "Human created and stored in database", Toast.LENGTH_LONG).show();

20. }

21. return rowId;

On définit un objet ContentValues dans lequel on place des paires (NomDeColonne, Valeur) à créer. Puis on utilise notre objet SQLiteDatabase pour faire l'insert en lui passant, le nom de la table, le nom d'une colonne (souvent null) et l'objet contenant la carte des paires (colonne, valeur) à insérer.

Pour l'update :

1. contentValues.clear();

2. contentValues.put(Constants.KEY_COL_NAME, "Georges");

3. contentValues.put(Constants.KEY_COL_FIRSTNAME, "Walter Bush");

5. // Update the database

6. rowId = db.update(Constants.MY_TABLE, contentValues, Constants.KEY_COL_ID + "=" + rowId, null);

8. // Test to see if the insertion was ok

9. if (rowId == -1) {

10. Toast.makeText(this, "Error when updating an human", Toast.LENGTH_LONG).show();

11. } else {

12. Toast.makeText(this, "Human updated in database", Toast.LENGTH_LONG).show();

13. }

14. return rowId;

On définit l'objet ContentValues dans lequel on place des paires (NomDeColonne, Valeur) à mettre à jour. Puis on utilise notre objet SQLiteDatabase pour faire l'update en lui passant le nom de la table, les valeurs à mettre et la clause where (ici la clef primaire de l'objet).

Pour le delete :

1. rowId = db.delete(DBOpenHelper.Constants.MY_TABLE,DBOpenHelper.Constants.KEY_COL_ID + "=" + rowId, null);

2. if (rowId == -1) {

3. Toast.makeText(this, "Error when deleting an human", Toast.LENGTH_LONG).show();

4. } else {

5. Toast.makeText(this, "Human deleted in database", Toast.LENGTH_LONG).show();

6. }

On utilise notre objet SQLiteDatabase pour faire le delete en lui passant le nom de la table et la clause where (ici la clef primaire de l'objet).

VI - Récupération des données de la table Query de la classe SQLiteDatabase

VI-1 - Parcourir le résultat des requêtes

Les résultats de requêtes sont renvoyés sous forme d'une liste de pointeurs vers les objets retournés. Cette liste de pointeurs se nomme Cursor. Cette classe possède de nombreuses méthodes :

- de mouvements (moveToFirst, moveToLast, moveNext, movePrevious, moveToPosition(int index)) ;

- de récupérations (getDouble, getFloat, getInt, getLong, getShort, getString, getBlob) ;

- d'informations (getColunmCount, getColumnName, getColumnIndex, getPosition, getCount...) ;

- d'états (isAfterLast, isBeforeFirst, isClosed, isFirst, isLast, isNull) ;

- d'autres méthodes de gestion de l'objet Cursor lui-même.

L'amalgame entre la liste de curseurs et la position du curseur est clair. On bouge dans la liste et en même temps quand on pointe sur un élément on l'interroge. Il faut s'y faire :

1. Cursor cursor = db.query(Constants.MY_TABLE,projections ,selection, selectionArg, groupBy,having,orderBy, maxResultsListSize);

2. // Then browse the result:

3. if (cursor.moveToFirst()){

4. // The elements to retrieve

5. Integer colId;

6. String name;

7. String firstname;

9. // The associated index within the cursor

10. int indexId=cursor.getColumnIndex(Constants.KEY_COL_ID);

11. int indexName=cursor.getColumnIndex(Constants.KEY_COL_NAME);

12. int indexFirstName=cursor.getColumnIndex(Constants.KEY_COL_FIRSTNAME);

14. // Browse the results list:

15. int count=0;

16. do {

17. colId=cursor.getInt(indexId);

18. name=cursor.getString(indexName);

19. firstname=cursor.getString(indexFirstName);

20. Toast.makeText(this, "Retrieve element :"+name+","+firstname+" ("+colId+")", Toast.LENGTH_LONG).show();

21. count++;

22. } while(cursor.moveToNext());

23. Toast.makeText(this, "The number of elements retrieved is "+count, Toast.LENGTH_LONG).show();

24. } else {

25. Toast.makeText(this, "No element found : ", Toast.LENGTH_LONG).show();

26. }

VI-2 - Effectuer une requête à la main

Il faut utiliser la méthode query de SQLiteDatabase.

Cette méthode prend en paramètres les éléments suivants :

- un booléen optionnel spécifiant si le résultat se compose d'éléments uniques (Boolean) ;

- le nom de la table à interroger (String) ;

- une projection sous forme de tableau de chaines listant les colonnes à inclure dans le résultat (String[]) ;

- une clause where avec des jokers (?) pour les paramètres si vous le souhaitez (String) ;

- la liste des paramètres qui remplaceront les jokers (?)(String[]) ;

- une clause groupBy (String) ;

- une clause orderBy dont la syntaxe est nomDeColonne + « ASC||Desc »(String) ;

- une limite maximale optionnelle du nombre d'éléments à récupérer (String).

Un exemple :

1. // Using man made query

2. // The projection define what are the column you want to retrieve

3. String[] projections=new String[] { Constants.KEY_COL_ID, Constants.KEY_COL_NAME, Constants.KEY_COL_FIRSTNAME };

5. // And then store the column index answered by the request (we present an other way to retireve data)

6. final int cursorIdColNumber=0,cursorNameColNumber=1,cursorFirstNameColNumber=2;

8. // To add a Where clause:

9. String selection=Constants.KEY_COL_HAIR_COLOR+"=?";

10. String[] selectionArg=new String[] {"blond"};

12. // The groupBy clause:

13. String groupBy=Constants.KEY_COL_EYES_COLOR;

15. // The having clause

16. String having=null;

18. // The order by clause (column name followed by Asc or DESC)

19. String orderBy = Constants.KEY_COL_AGE+"  ASC";

21. // Maximal size of the results list

22. String maxResultsListSize="60";

23. Cursor cursor = db.query(Constants.MY_TABLE,projections ,selection, selectionArg, groupBy,having,orderBy, maxResultsListSize);

24. displayResults(cursor);

VI-3 - Effectuer une requête avec SQLiteQueryBuilder

Vous pouvez utiliser aussi l'objet SQLiteQueryBuilder qui permet d'effectuer des unions et quelques autres opérations de ce type.

Nous reprenons dans l'exemple uniquement une recherche simple :

1. // Using SQLiteQueryBuilder

2. // The projection define what are the column you want to retrieve

3. String[] projections=new String[] { Constants.KEY_COL_ID, Constants.KEY_COL_NAME, Constants.KEY_COL_FIRSTNAME };

5. // And then store the column index answered by the request (we present an other way to retireve data)

6. final int cursorIdColNumber=0,cursorNameColNumber=1,cursorFirstNameColNumber=2;

8. // Adding a where clause:

9. String selection=Constants.KEY_COL_HAIR_COLOR+"=?";

10. String[] selectionArg=new String[] {"blond"};

12. // The groupBy clause:

13. String groupBy=Constants.KEY_COL_EYES_COLOR;

14. // The having clause

15. String having=null;

17. // The order by clause (column name followed by Asc or DESC)

18. String orderBy = Constants.KEY_COL_AGE+"  ASC";

20. // Using the QueryBuilder

21. // Create a Query SQLite object

22. SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

23. qb.setTables(Constants.MY_TABLE);

24. // qb.appendWhere(Constants.KEY_COL_HAIR_COLOR+ "=blond");

25. qb.setDistinct(true);

26. cursor=qb.query(db,projections ,selection, selectionArg, groupBy,having,orderBy);

27. displayResults(cursor);

VII - Gestion des transactions

Les transactions peuvent avoir un listener, ce qui est une bonne pratique, mais vous pouvez vous en passer (ce qui est une mauvaise pratique).

Le pattern standard d'utilisation des transactions est :

soit :

db.beginTransactionWithListener(listener);

soit :

1. db.beginTransaction();

2. try {

3. ...

4. db.setTransactionSuccessful();

5. } finally {

6. db.endTransaction();

7. }

Le listener est du type : public void beginTransactionWithListener (SQLiteTransactionListener transactionListener)

VIII - Un exemple complet

Cet exemple montre comment mettre en place une base de données et communiquer avec elle à partir d'une activité. Il y a deux classes, la classe d'instanciation de la base et la classe d'utilisation de cette base.

La classe de création :

1. public class DBOpenHelper extends SQLiteOpenHelper {

2. // @goals This class aims to show the constant to use for the DBOpenHelper */

3. public static class Constants implements BaseColumns {

4. // The database name

5. public static final String DATABASE_NAME = "myData.db";

7. // The database version

8. public static final int DATABASE_VERSION = 1;

10. // The table Name

11. public static final String MY_TABLE = "Human";

13. // Noms de colonnes

14. // /!\Si vous utilisez une base de données, les noms des colonnes ont

15. // les mêmes que ceux de

16. // votre base, de même pour les index.

17. // My Column ID and the associated explanation for end-users

18. public static final String KEY_COL_ID = "_id";// Mandatory

20. // My Column Name and the associated explanation for end-users

21. public static final String KEY_COL_NAME = "name";

23. // My Column First Name and the associated explanation for end-users

24. public static final String KEY_COL_FIRSTNAME = "firstName";

26. // My Column Eyes Color and the associated explanation for end-users

27. public static final String KEY_COL_EYES_COLOR = "eyesColor";

29. // My Column Hair color and the associated explanation for end-users

30. public static final String KEY_COL_HAIR_COLOR = "hairColor";

32. // My Column age and the associated explanation for end-users

33. public static final String KEY_COL_AGE = "age";

35. // Index des colonnes

36. // The index of the column ID

37. public static final int ID_COLUMN = 1;

39. // The index of the column NAME

40. public static final int NAME_COLUMN = 2;

42. // The index of the column FIRST NAME

43. public static final int FIRSTNAME_COLUMN = 3;

45. // The index of the column EYES COLOR

46. public static final int EYES_COLOR_COLUMN = 4;

48. // The index of the column HAIR COLOR

49. public static final int HAIR_COLOR_COLUMN = 5;

51. // The index of the column AGE

52. public static final int AGE_COLUMN = 6;

53. }

55. // The static string to create the database.

56. private static final String DATABASE_CREATE = "create table "

57. + Constants.MY_TABLE + "(" + Constants.KEY_COL_ID

58. + " integer primary key autoincrement, " + Constants.KEY_COL_AGE

59. + " INTEGER, " + Constants.KEY_COL_NAME + " TEXT, "

60. + Constants.KEY_COL_FIRSTNAME + " TEXT, "

61. + Constants.KEY_COL_EYES_COLOR + " TEXT, "

62. + Constants.KEY_COL_HAIR_COLOR + " TEXT) ";

64. /**

65. * @param context

66. * @param name

67. * @param factory

68. * @param version

69. */

70. public DBOpenHelper(Context context, String name, CursorFactory factory,

71. int version) {

72. super(context, name, factory, version);

73. }

75. @Override

76. public void onCreate(SQLiteDatabase db) {

77. // Create the new database using the SQL string Database_create

78. db.execSQL(DATABASE_CREATE);

80. }

82. @Override

83. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

84. Log.w("DBOpenHelper", "Mise à jour de la version " + oldVersion

85. + " vers la version " + newVersion

86. + ", les anciennes données seront détruites ");

87. // Drop the old database

88. db.execSQL("DROP TABLE IF EXISTS " + Constants.MY_TABLE);

89. // Create the new one

90. onCreate(db);

91. // or do a smartest stuff

92. }

93. }

La classe d'utilisation :

1. public class DataBaseTuto extends Activity {

2. // The database

3. private SQLiteDatabase db;

4. // The database creator and updater helper

5. DBOpenHelper dbOpenHelper;

7. // Called when the activity is first created. */

8. @Override

9. public void onCreate(Bundle savedInstanceState) {

10. super.onCreate(savedInstanceState);

11. setContentView(R.layout.main);

13. // Create or retrieve the database

14. dbOpenHelper = new DBOpenHelper(this, Constants.DATABASE_NAME, null,

15. Constants.DATABASE_VERSION);

17. // open the database

18. openDB();

20. // Insert a new record

21. // -------------------

22. ContentValues contentValues = new ContentValues();

23. long rowId = insertRecord(contentValues);

25. // update that line

26. // ----------------

27. rowId = updateRecord(contentValues, rowId);

29. // Query that line

30. // ---------------

31. queryTheDatabase();

33. // And then delete it:

34. // -------------------

35. deleteRecord(rowId);

36. }

38. /*********************************************************************************/

39. /** Managing LifeCycle and database open/close operations *********************************/

40. /*********************************************************************************/

41. @Override

42. protected void onResume() {

43. super.onResume();

44. openDB();

45. }

47. @Override

48. protected void onPause() {

49. super.onPause();

50. closeDB();

51. }

53. /**

54. * * Open the database* *

55. *

56. * @throws SQLiteException

57. */

58. public void openDB() throws SQLiteException {

59. try {

60. db = dbOpenHelper.getWritableDatabase();

61. } catch (SQLiteException ex) {

62. db = dbOpenHelper.getReadableDatabase();

63. }

64. }

66. /** *Close Database */

67. public void closeDB() {

68. db.close();

69. }

71. /****************************************************************************************/

72. /** Managing Records **********************************************************************/

73. /****************************************************************************************/

74. /**

75. * Insert a record

76. *

77. * @param contentValues

78. *            (an empty contentValues)

79. * @return the inserted row id

80. */

81. private long insertRecord(ContentValues contentValues) {

82. // Assign the values for each column.

83. contentValues.put(Constants.KEY_COL_NAME, "name");

84. contentValues.put(Constants.KEY_COL_FIRSTNAME, "firstName");

85. contentValues.put(Constants.KEY_COL_EYES_COLOR, "green");

86. contentValues.put(Constants.KEY_COL_HAIR_COLOR, "blond");

87. contentValues.put(Constants.KEY_COL_AGE, 6);

89. // Insert the line in the database

90. long rowId = db.insert(Constants.MY_TABLE, null, contentValues);

92. // Test to see if the insertion was ok

93. if (rowId == -1) {

94. Toast.makeText(this, "Error when creating an human",

95. Toast.LENGTH_LONG).show();

96. } else {

97. Toast.makeText(this, "Human created and stored in database",

98. Toast.LENGTH_LONG).show();

99. }

100. return rowId;

101. }

103. /**

104. * * Update a record

105. *

106. * @param contentValues

107. * @param rowId

108. * @return the updated row id

109. */

110. private long updateRecord(ContentValues contentValues, long rowId) {

111. contentValues.clear();

112. contentValues.put(Constants.KEY_COL_NAME, "Georges");

113. contentValues.put(Constants.KEY_COL_FIRSTNAME, "Walter Bush");

114. // update the database

115. rowId = db.update(Constants.MY_TABLE, contentValues,

116. Constants.KEY_COL_ID + "=" + rowId, null);

117. // test to see if the insertion was ok

118. if (rowId == -1) {

119. Toast.makeText(this, "Error when updating an human",

120. Toast.LENGTH_LONG).show();

121. } else {

122. Toast.makeText(this, "Human updated in database", Toast.LENGTH_LONG)

123. .show();

124. }

125. return rowId;

126. }

128. /**

129. * * Delete a Record *

130. *

131. * @param rowId

132. */

133. private void deleteRecord(long rowId) {

134. rowId = db.delete(DBOpenHelper.Constants.MY_TABLE,

135. DBOpenHelper.Constants.KEY_COL_ID + "=" + rowId, null);

136. if (rowId == -1) {

137. Toast.makeText(this, "Error when deleting an human",

138. Toast.LENGTH_LONG).show();

139. } else {

140. Toast.makeText(this, "Human deleted in database", Toast.LENGTH_LONG)

141. .show();

142. }

143. }

145. /**

146. * Query a the database

147. */

148. private void queryTheDatabase() {

149. // Using man made query

150. // The projection define what are the column you want to retrieve

151. String[] projections = new String[] { Constants.KEY_COL_ID,

152. Constants.KEY_COL_NAME, Constants.KEY_COL_FIRSTNAME };

153. // And then store the column index answered by the request (we present

154. // an other way to

155. // retireve data)

156. final int cursorIdColNumber = 0, cursorNameColNumber = 1, cursorFirstNameColNumber = 2;

157. // To add a Where clause you can either do that:

158. // qb.appendWhere(Constants.KEY_COL_HAIR_COLOR+ "=blond");

159. // Or that:

160. String selection = Constants.KEY_COL_HAIR_COLOR + "=?";

161. String[] selectionArg = new String[] { "blond" };

162. // The groupBy clause:

163. String groupBy = Constants.KEY_COL_EYES_COLOR;

164. // The having clause

165. String having = null;

166. // The order by clause (column name followed by Asc or DESC)

167. String orderBy = Constants.KEY_COL_AGE + "  ASC";

168. // Maximal size of the results list

169. String maxResultsListSize = "60";

170. Cursor cursor = db.query(Constants.MY_TABLE, projections, selection,

171. selectionArg, groupBy, having, orderBy, maxResultsListSize);

172. displayResults(cursor);

174. // Using the QueryBuilder

175. // Create a Query SQLite object

176. SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

177. qb.setTables(Constants.MY_TABLE);

178. // qb.appendWhere(Constants.KEY_COL_HAIR_COLOR+ "=blond");

179. qb.setDistinct(true);

180. cursor = qb.query(db, projections, selection, selectionArg, groupBy,

181. having, orderBy);

182. displayResults(cursor);

183. }

185. /**

186. * Display the results stored in the cursor

187. *

188. * @param cursor

189. */

190. private void displayResults(Cursor cursor) {

191. // then browse the result:

192. if (cursor.moveToFirst()) {

193. // The elements to retrieve

194. Integer colId;

195. String name;

196. String firstname;

197. // The associated index within the cursor

198. int indexId = cursor.getColumnIndex(Constants.KEY_COL_ID);

199. int indexName = cursor.getColumnIndex(Constants.KEY_COL_NAME);

200. int indexFirstName = cursor

201. .getColumnIndex(Constants.KEY_COL_FIRSTNAME);

202. // Browse the results list:

203. int count = 0;

204. do {

205. colId = cursor.getInt(indexId);

206. name = cursor.getString(indexName);

207. firstname = cursor.getString(indexFirstName);

208. Toast.makeText(

209. this,

210. "Retrieve element :" + name + "," + firstname + " ("

211. + colId + ")", Toast.LENGTH_LONG).show();

212. count++;

213. } while (cursor.moveToNext());

214. Toast.makeText(this,

215. "The number of elements retrieved is " + count,

216. Toast.LENGTH_LONG).show();

217. } else {

218. Toast.makeText(this, "No element found : ", Toast.LENGTH_LONG)

219. .show();

220. }

221. }

222. }

IX - Remerciements

Nous tenons à remercier Claude Leloup pour la relecture orthographique de cet article.