mercredi 25 décembre 2013

School Matière: Apprendre à manipuler une base de données Sqlite

Je sais très bien que vous ne m'attendiez pas de ci tôt mais me revoilà avec de nouveaux tutos. Celui d’aujourd’hui concerne SQLite sous Android. C’est toujours utile de pouvoir stocker quelques données dans une application. Les tables que l’on créé avec SQLite doivent bien entendu être simple tout comme les requêtes que vous ferez dessus. Rappelez-vous que l’on n’est pas sur des méga serveurs ultra puissants, mais simplement sur un mobile ! ;)



Pour notre exemple, nous allons créer une mini base de données pour enregistrer les matières d'un élève. Durant ce tuto, nous utiliserons les classes suivantes :

SQLiteOpenHelper qui est une classe d’assistance pour gérer la création de bases de données et la gestion des versions.
ContentValue, cette classe est utilisée pour stocker un ensemble de valeurs que le ContentResolver peut traiter.
Cursor est une interface qui donne accès en lecture-écriture à l’ensemble des résultats retournés par une requête de base de données.
On va donc commencer doucement avec la création de la classe Matière (très simple pour notre exemple). Ce tuto sera  un petit projet avec tous les éléments dont vous aurez besoin pour évoluer dans la création des applications mobile.

Code JAVA Matiere.java:
  Après avoir créé un nouveau projet, on va créer une nouvelle classe qu'on va appeler Matiere.
Cette classe est très simple puisque dans notre cas une Matière est définie par un Identifiant "idmat", un libélé "libmat" et un coefficient "coefmat". On crée le constructeur ainsi que les getter et les setter et le tour est joué. Voici le code :

package com.school.matiere;

public class Matiere {
int idmat;
String libmat;
int coefmat;

public Matiere() {
// TODO Auto-generated constructor stub
}

public Matiere(int idmat) {
this.idmat = idmat;
}
public Matiere(int idmat, String libmat, int coefmat) {
this.idmat = idmat;
this.libmat = libmat;
this.coefmat = coefmat;
}

public Matiere(String libmat, int coefmat) {
this.libmat = libmat;
this.coefmat = coefmat;
}

public Matiere(String libmat) {
this.libmat = libmat;
}

public int getIdmat() {
return idmat;
}

public void setIdmat(int idmat) {
this.idmat = idmat;
}

public String getLibmat() {
return libmat;
}

public void setLibmat(String libmat) {
this.libmat = libmat;
}

public int getCoefmat() {
return coefmat;
}

public void setCoefmat(int coefmat) {
this.coefmat = coefmat;
}

}

Maintenant nous allons faire une nouvelle classe que j’ai appelée DatabaseHelper et qui « extends » de SQLiteOpenHelper. Cette classe va nous permettre de définir la table qui sera produite lors de l’instanciation de celle-ci. Elle va nous permettre aussi de gérer l’insertion, la suppression, la modification de livres dans la BDD (Base De Données) ainsi que de faire des requêtes pour récupérer une Matière contenue dans la BDD. Le code est très simple vous allez voir, et je l’ai commentée :

package com.school.matiere.db;

import java.util.ArrayList;
import java.util.List;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;
import com.school.matiere.Matiere;

public class DatabaseHelper extends SQLiteOpenHelper {

Context context;
SQLiteDatabase db;
public static final String MOY_DB = "matiere.db";
private static final int VERSION_BDD = 1;

// Matiere
public static final String TABLE_MATIERE = "TMatiere";
public static final String IDMAT = "id";
public static final String LIBMAT = "libmat";
public static final String COEFMAT = "coefmat";
public static final String CREATE_MATIERE_TABLE = "CREATE TABLE "
+ TABLE_MATIERE + " (" + IDMAT
+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + LIBMAT
+ " TEXT NOT NULL UNIQUE, " + COEFMAT + " INTEGER NOT NULL);";

public DatabaseHelper(Context context, String name, 
CursorFactory factory, int version) {
super(context, MOY_DB, factory, VERSION_BDD);
// this.context = context;
}

@Override
public void onCreate(SQLiteDatabase db) {
//on créé la table à partir de la requête écrite dans la variable CREATE_MATIERE_TABLE
db.execSQL(CREATE_MATIERE_TABLE);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//On peut fait ce qu'on veut ici moi j'ai décidé
                // de supprimer la table et de la recréer
//comme ça lorsque je change la version les id repartent de 0
Toast.makeText(
context,
"Mise à jour de la Base de données version " + oldVersion
+ " vers " + newVersion, Toast.LENGTH_SHORT).show();
db.execSQL("DROP TABLE IF EXISTS " + TABLE_MATIERE);

onCreate(db);
}

public void insererMatiere(String libmat, int coefmat) {
//on ouvre la BDD en écriture
SQLiteDatabase db = this.getWritableDatabase();
//Création d'un ContentValues (fonctionne comme une HashMap)
ContentValues values = new ContentValues();
//on lui ajoute une valeur associé à une clé 
//(qui est le nom de la colonne dans laquelle on veut mettre la valeur)
values.put(LIBMAT, libmat);
values.put(COEFMAT, coefmat);
//on insère l'objet dans la BDD via le ContentValues
db.insert(TABLE_MATIERE, LIBMAT, values);
//on ferme la base de données
db.close();
}



public List<Matiere> getLabelsMat() {
List<Matiere> mat = new ArrayList<Matiere>();
// requete de sélection de tous les enregistrements contenus dans la BDD
String selectQuery = "Select " + IDMAT + " as _id , " + LIBMAT + ", "
+ COEFMAT + " from " + TABLE_MATIERE + " order by " + LIBMAT;
//on ouvre la BDD en lecture
SQLiteDatabase db = this.getReadableDatabase();
//Récupère dans un Cursor les valeur correspondant à une Matiere contenu dans la BDD
//(ici on sélectionne la Matière grâce à son libélé)
Cursor cursor = db.rawQuery(selectQuery, null);

// recuppérer tous les enregistrements et les ajouter au ArrayList
if (cursor.moveToFirst()) {
do {
mat.add(new Matiere(cursor.getInt(0), cursor.getString(1),
cursor.getInt(2)));
} while (cursor.moveToNext());
}

// fermer les connexions
cursor.close();
db.close();

// retourne une instance de Matière
return mat;
}

               //cette fonction va nous permettre de compter
              // le nombre de matière enregistré dans la BDD
              //mais nous ne l'utiliserons pas cette fois-ci. c'est juste pour votre connaissance
public int getMatRowCount() {
String countQuery = "SELECT  * FROM " + TABLE_MATIERE;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
int rowCount = cursor.getCount();
db.close();
cursor.close();
// return row count
return rowCount;
}

public int UpdateMat(Matiere mat) {
//La mise à jour d'une Matiere dans la BDD fonctionne
                // plus ou moins comme une insertion
//il faut simplement préciser quelle Matiere 
                //on doit mettre à jour grâce à l'IDMAT
SQLiteDatabase db = this.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put(LIBMAT, mat.getLibmat());
cv.put(COEFMAT, mat.getCoefmat());
return db.update(TABLE_MATIERE, cv, IDMAT + "=?",
new String[] { String.valueOf(mat.getIdmat()) });

}

public void DeleteMat(Matiere mat) {
//Suppression d'une Matiere de la BDD grâce à l'IDMAT
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_MATIERE, IDMAT + "=?",
new String[] { String.valueOf(mat.getIdmat()) });
db.close();

}

}

Avant de Créer la classe qui va nous permettre d'afficher la liste des matières enregistré, créons ensemble la classe ListAdapterMatiere qui va hériter de la classe BaseAdapter et directement relié a la Classe ListMatiere.java que bous créerons dans la suite. cette classe permet de récupérer tous les enregistrements de la BDD, d'affecter une position à chaque enregistrement dans la BDD pour faciliter l'indexation en vu d'un affichage, d'une modification ou d'une suppression de la matière sélectionné.

Voici le code:

package com.school.matiere;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import com.school.matiere.db.DatabaseHelper;

import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class ListAdapterMatiere extends BaseAdapter {

// Declare Variables
Context mContext;
LayoutInflater inflater;
private List<Matiere> listMatiere = null;
private ArrayList<Matiere> arraylist;

public ListAdapterMatiere(Context context, List<Matiere> listMatiere) {
mContext = context;
this.listMatiere = listMatiere;
inflater = LayoutInflater.from(mContext);
this.arraylist = new ArrayList<Matiere>();
this.arraylist.addAll(listMatiere);
}

public class ViewHolder {
TextView libMat;
TextView coefMat;
}

@Override
public int getCount() {
return listMatiere.size();
}

@Override
public Matiere getItem(int position) {
return listMatiere.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(final int position, View view, ViewGroup parent) {
final ViewHolder holder;
if (view == null) {
holder = new ViewHolder();
view = inflater.inflate(R.layout.matiere_list_item, null);
// Locate the TextViews in listview_item.xml
holder.libMat = (TextView) view.findViewById(R.id.mat_item);
holder.coefMat = (TextView) view.findViewById(R.id.coef_item);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
// Set the results into TextViews
holder.libMat.setText(listMatiere.get(position).getLibmat());
Log.d("ListAdapter", "" + listMatiere.get(position).getCoefmat());
holder.coefMat.setText(String.valueOf(listMatiere.get(position)
.getCoefmat()));
view.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {

}
});

view.setOnLongClickListener(new OnLongClickListener() {

@Override
public boolean onLongClick(View v) {
int idMati = (listMatiere.get(position).getIdmat());
String libMati = (listMatiere.get(position).getLibmat());
int coefMati = (listMatiere.get(position).getCoefmat());
Intent intent = new Intent(mContext, EditMatiere.class);
intent.putExtra(DatabaseHelper.IDMAT, idMati);
intent.putExtra(DatabaseHelper.LIBMAT, libMati);
intent.putExtra(DatabaseHelper.COEFMAT, coefMati);
mContext.startActivity(intent);

return false;
}
});
return view;
}

// Filter Class
public void filter(String charText) {
charText = charText.toLowerCase(Locale.getDefault());
listMatiere.clear();
if (charText.length() == 0) {
listMatiere.addAll(arraylist);
} else {
for (Matiere wp : arraylist) {
if (wp.getLibmat().toLowerCase(Locale.getDefault())
.contains(charText)) {
listMatiere.add(wp);
}
}
}
notifyDataSetChanged();
}

}


Créons maintenant notre écran principale qui va nous permettre d'afficher la liste des matières enregistrée dans la BDD. Nous allons créer une classe qu'on appellera ListMatiere.java qui sera une Activité. Dans cette activité, nous allons ajouter un SerchText(rechercher une matière dans la liste).



Voici le code:

 package com.school.matiere;


import java.util.Locale;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.school.matiere.db.DatabaseHelper;

public class ListMatiere extends Activity {

protected EditText searchText;
DatabaseHelper dbhelper;
protected Cursor cursor;
ListAdapterMatiere adapter;
public static ListView liste;
TextView libMat;
TextView coefi;
Context mcont;
ImageButton btnSearch, btnAdd;
View viewMat;
int sclic = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.matiere_list);
searchText = (EditText) findViewById(R.id.searchTextMat);
liste = (ListView) findViewById(R.id.listmat);
libMat = (TextView) findViewById(R.id.labelmat);
btnSearch = (ImageButton) findViewById(R.id.btnSearchMat);
btnAdd = (ImageButton) findViewById(R.id.btnAddMat);
viewMat = findViewById(R.id.viewMat);
mcont = getApplicationContext();
setInvisible();

//Affichons la liste des matières
try {
LoadListMat();
} catch (Exception e) {
Toast.makeText(mcont, "Impossible d'afficher \n" + e.toString(),
Toast.LENGTH_SHORT).show();
}
//
btnAdd.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
setInvisible();
//Appel de l'activité qui va nous permettre d'ajouter les matière
Intent intent = new Intent(mcont, AddMatiere.class);
startActivity(intent);
}
});
// gestion du searchText
searchText.addTextChangedListener(textWatcher);
btnSearch.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
sclic++;
if (sclic == 1) {
setVisible();
} else if (sclic == 2) {
setInvisible();
sclic = 0;
}
}
});
}

// EditText TextWatcher
// Création du SearchText
private TextWatcher textWatcher = new TextWatcher() {

@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
// if (searchText.getText().length() > 0) {
String text = searchText.getText().toString()
.toLowerCase(Locale.getDefault());
adapter.filter(text);
// }

}

@Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub

}

@Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub

}

};

//Création de l'affichage de la liste
public void LoadListMat() {
//on crée une instance de la BDD (ouverture)
dbhelper = new DatabaseHelper(mcont, null, null, 1);
boolean ok = true;
try {
adapter = new ListAdapterMatiere(mcont, dbhelper.getLabelsMat());
liste.setAdapter(adapter);
Log.i("LISTMatiere 3", "OK");
} catch (Exception ex) {
ok = false;
AlertDialog.Builder b = new AlertDialog.Builder(mcont);
b.setMessage(ex.toString());
b.show();
} finally {
if (ok) {
dbhelper.close();
}
}

}
// c'est un petit bonus pour vous
private void setVisible() {
// TODO Auto-generated method stub
viewMat.setVisibility(View.GONE);
searchText.setVisibility(View.VISIBLE);
// Focus on EditText
searchText.requestFocus();

// Forcer le keyboard à montrer le focus du EditText
InputMethodManager imm = (InputMethodManager) mcont
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}

// c'est un petit bonus pour vous
private void setInvisible() {
// TODO Auto-generated method stub
searchText.setText("");
searchText.clearFocus();
searchText.setVisibility(View.GONE);
viewMat.setVisibility(View.VISIBLE);
sclic = 0;
}

@Override
public void onResume() {
// TODO Auto-generated method stub
super.onResume();
LoadListMat();
adapter.notifyDataSetChanged();
}

}

Écrivons maintenant le code de la classe qui va nous permettre d'ajouter nos matière dans la BDD, je l'ai nommée AddMatiere. c'est une classe très simple, vous verrez:

package com.school.matiere;

import com.school.matiere.db.DatabaseHelper;

import android.app.Activity;
import android.os.Bundle;
import android.text.Spannable;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class AddMatiere extends Activity {

EditText txt_lib_mat;
EditText txt_coef_mat;
Button btnAdd;
Button btnBack;

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.matiere_add);
setTitle("Ajouter Matière");
btnAdd = (Button) findViewById(R.id.btn_save_mat);
btnBack = (Button) findViewById(R.id.btn_back_mat);
txt_lib_mat = (EditText) findViewById(R.id.lib_mat);
txt_coef_mat = (EditText) findViewById(R.id.coef_mat);

btnAdd.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
SaveMatiere();
}
});

btnBack.setOnClickListener(new View.OnClickListener() {
//fermer AddMatiere pour revenir a la liste des matière qui est l'écran précédent
@Override
public void onClick(View v) {
finish();
}
});
}

public void SaveMatiere() {
boolean ok = true;
//verifier que les champs contiennet des valeurs avant de prétendre les enregistrer
if((txt_coef_mat.getText().toString().length()>0)
&&(txt_lib_mat.getText().toString().length()>0)){
try {
//recuperation d'une valeure entiere dans un EditText
Spannable spn = txt_coef_mat.getText();
int coef = Integer.valueOf(spn.toString());
//recuperation du libélé de la matière
String lib = txt_lib_mat.getText().toString();
//instanciation de la BDD
DatabaseHelper db = new DatabaseHelper(getApplicationContext(), null, null, 1);
//compte le nombre de matière du depart juste pour verifier
int nbMat1 = db.getMatRowCount();
//verification des actions effectué dans le Logcat
Log.i("SaveMatiere", "Nombre matieres depart " + nbMat1);
Log.i("SaveMatiere Coef 1", "Coef: " + coef);
Log.i("SaveMatiere", "matiere: " + lib);
//insersion des élément saisi
db.insererMatiere(lib, coef);
int nbMat2 = db.getMatRowCount();
Log.i("LoadListmat", "Nombre matieres fin " + nbMat2);
} catch (Exception ex) {
ok = false;
Toast.makeText(getApplicationContext(),
"  Erreur \n" + ex.toString(), Toast.LENGTH_LONG).show();
finish();
} finally {
if (ok) {
//si enregistrement OK afficher un toast
Toast.makeText(getApplicationContext(), "Enregistrement effectué avec succès",
Toast.LENGTH_LONG).show();
}
//fermer AddMatiere pour revenir a la liste des matière qui est l'écran précédent
finish();
}
}else
//si les champs sont vide afficher ce toast
Toast.makeText(getApplicationContext(), "Champs Vide",
Toast.LENGTH_LONG).show();
}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//si l'utilisateur clic sur back fermer AddMatiere pour revenir
//a la liste des matière qui est l'écran précédent
if (keyCode == KeyEvent.KEYCODE_BACK) {
finish();
}
return false;

}
}


Nous allons maintenant gérer la mise à jour et la suppression des matières. Notons que cette classe que nous allons créer est appeler a partir de la classe ListAdapterMatiere et elle permet d'afficher les éléments d'une matière après un Long Click. c'est le même procédé que la classe AddMatiere. nous la nommerons EditMatiere. cette fois-ci pas trop de commentaire:



package com.school.matiere;

import com.school.matiere.db.DatabaseHelper;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.text.Spannable;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class EditMatiere extends Activity {

EditText txt_lib_mat;
EditText txt_coef_mat;
Button btnAdd;
Button btnBack;
Button btnSup;
String libmat;
int idmat, coefmat;
DatabaseHelper db;

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.matiere_edit);
setTitle("Modifier Matière");
btnAdd = (Button) findViewById(R.id.btn_edit_mat);
btnBack = (Button) findViewById(R.id.btn_back_mat_edit);
btnSup = (Button) findViewById(R.id.btn_sup_mat);
txt_lib_mat = (EditText) findViewById(R.id.lib_mat_edit);
txt_coef_mat = (EditText) findViewById(R.id.coef_mat_edit);

idmat = getIntent().getIntExtra(DatabaseHelper.IDMAT, 0);
coefmat = getIntent().getIntExtra(DatabaseHelper.COEFMAT, 0);
libmat = getIntent().getStringExtra(DatabaseHelper.LIBMAT);

txt_lib_mat.setText(libmat);
txt_coef_mat.setText(""+coefmat);

btnAdd.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
editMatiere();
}
});

btnBack.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
finish();
}
});

btnSup.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
new AlertDialog.Builder(EditMatiere.this)
   .setTitle("Confirmation")
   .setIcon(android.R.drawable.ic_menu_delete)
   .setMessage("Etes vous sûr de vouloir effectuer cette action?")
   .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
       @Override
public void onClick(DialogInterface dialog, int which) {          
        Matiere mat = new Matiere(idmat);
supMatiere(mat);
       
       }
   })
   .setNegativeButton("Non", new DialogInterface.OnClickListener() {
       @Override
public void onClick(DialogInterface dialog, int which) { 
           // do nothing
       }
   })
   .show();

}
});
}

public void editMatiere() {
boolean ok = true;
if((txt_coef_mat.getText().toString().length()>0)
&&(txt_lib_mat.getText().toString().length()>0)){
try {
Spannable spn = txt_coef_mat.getText();
int coef = Integer.valueOf(spn.toString());
String lib = txt_lib_mat.getText().toString();

db = new DatabaseHelper(getApplicationContext(), null, null, 1);
Log.i(" Coef 1", "Coef: " + coef);
Log.i(" Matiere 1", "matiere: " + lib);
Matiere mat = new Matiere(idmat, lib, coef);
db.UpdateMat(mat);
} catch (Exception ex) {
ok = false;
Toast.makeText(getApplicationContext(),
"  Erreur \n" + ex.toString(), Toast.LENGTH_LONG).show();
finish();
} finally {
if (ok) {

Toast.makeText(getApplicationContext(), "Mise à jour effectué avec succès",
Toast.LENGTH_LONG).show();
}
finish();
}
} else
Toast.makeText(getApplicationContext(), "Champs vide",
Toast.LENGTH_LONG).show();

}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {

if (keyCode == KeyEvent.KEYCODE_BACK) {
finish();
}
return false;

}

public void supMatiere(Matiere mati) {
boolean ok = true;

try {
db = new DatabaseHelper(getApplicationContext(), null, null, 1);
db.DeleteMat(mati);
} catch (Exception ex) {
ok = false;
Toast.makeText(getApplicationContext(),
"  Erreur \n" + ex.toString(), Toast.LENGTH_LONG).show();
finish();
} finally {
if (ok) {
Toast.makeText(this, "Supprimé avec succès", Toast.LENGTH_LONG)
.show();
db.close();
finish();
}
}
}
}





Nous avons terminé avec ce tuto, j'espère qu'il vous sera très utile et que vous en ferez bon usage.


NB: Tuto tiré de l'application SchoolKit que j'ai conçu.

Aucun commentaire:

Enregistrer un commentaire