android_sqlite

SQLite con Android

Il SO Android mette a disposizione gli strumenti per operare con database SQLite: per gestirli è sufficiente implementare una classe “helper”.

Per prima cosa creiamo un’ interfaccia in cui memorizzare i nomi delle colonne e delle tavole del database, per non doverli scrivere ogni volta: estendiamo l’ interfaccia BaseColumns

public interface ProvinciaTable extends BaseColumns {
	String TABLE_NAME = "province";
	String CODICE = "codice";
	String NOME = "nome";

	String[] COLUMNS = new String[] {_ID, CODICE, NOME};
}

si ricordi che in una interfaccia una costante è implicitamente public static final.

Creazione e popolamento del database

L’ SDK ci fornisce la classe astratta SQLiteOpenHelper per gestire “facilmente” i database SQLite: i suoi metodi onCreate e onUpgrade sono astratti, quindi siamo obbligati ad implementarli.
La classe si prenderà cura di aprire il database (se esiste), di crearlo (se non esiste), e di aggiornarlo: userà le transazioni per avere il database sempre in uno stato sensibile.

Vediamo il costruttore:

public class DatabaseHelper extends SQLiteOpenHelper {

	private static final String DATABASE_NAME = "devAPP.db";
	private static final int SCHEMA_VERSION = 1;

	public DatabaseHelper(Context context) {
		super(context, DATABASE_NAME, null, SCHEMA_VERSION);
	}
	//...
}

Lo schema_version serve per gestire gli aggiornamenti del database.
Vediamo ora il callback onCreate, che viene chiamato soltanto quando un database deve essere creato:

public void onCreate(SQLiteDatabase db) {
	// formatto una stringa sql, come si fa con printf in C, con i comandi per creare il database
	String sql = "CREATE TABLE {0} ({1} INTEGER PRIMARY KEY AUTOINCREMENT, {2} TEXT NOT NULL,{3} TEXT NOT NULL);";
	db.execSQL(MessageFormat.format(sql, ProvinciaTable.TABLE_NAME, ProvinciaTable._ID, ProvinciaTable.CODICE, ProvinciaTable.NOME));

	inserisciProvincia(db, "Agrigento", "AG");
	inserisciProvincia(db, "Alessandria", "AL");
	inserisciProvincia(db, "Ancona", "AN");
	//...
	inserisciProvincia(db, "Viterbo", "VT");
}

Per inserire i valori usiamo questo metodo:

private void inserisciProvincia(SQLiteDatabase db, String nome, String codice) {
	ContentValues v = new ContentValues();
	v.put(ProvinciaTable.CODICE, codice);
	v.put(ProvinciaTable.NOME, nome);
	db.insert(ProvinciaTable.TABLE_NAME, null, v);
}

il metodo insert della classe SQLiteDatabase richiede il terzo parametro di tipo ContentValues: questo serve a “mappare” un dato nella rispettiva colonna.
Il secondo parametro invece è opzionale e riguarda la gestione dell’ inserimento di una riga di dati nulli: se posto a true, fa si che vengano inseriti dei NULL nel database invece di restituire errore.

Esecuzione di una query

I metodi finora visti servono a creare e popolare il database, ma ancora non abbiamo incontrato un evento che possa chiamarli.

La classe SQLiteOpenHelper offre due metodi per accedere al database:

  • public synchronized SQLiteDatabase getReadableDatabase ()
  • public synchronized SQLiteDatabase getWritableDatabase ()

Il primo metodo crea o apre il database e restituisce lo stesso oggetto che restituirebbe getWritableDatabase, a meno che non sorga un problema che costringe ad aprire il database in sola lettura (ad esempio un disco pieno).
Il secondo metodo è più restrittivo: crea o apre il database, ma richiede esclusivamente un accesso in scrittura, e lancia una SQLiteException se ciò non è possibile.

Dunque, per accedere al database (eventualmente dopo averlo creato ex-novo), è necessario chiamare uno dei due metodi ora visti.
Implemento allora un nuovo metodo che chiamerò dalla Activity principale:

public Cursor getProvince() {
	return (getReadableDatabase().query(
		ProvinciaTable.TABLE_NAME, ProvinciaTable.COLUMNS, null, null, null, null, ProvinciaTable.NOME));
}

dentro questo metodo avviene la chiamata a getReadableDatabase() che ci assicura un accesso al database (sarebbe più raffinato creare un blocco try/catch SQLiteException per controllare eventuali errori), ed effettuo una query sul SQLiteDatabase restituito.

Tra i vari metodi query uso

public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)

i cui parametri sono:

  • il nome della tabella
  • l’ array con i nomi delle colonne (vedere interfaccia creata all’ inizio)
  • 4 parametri per definire la clausola WHERE, argomenti per il bind, la clausola GROUP BY, e la clausola HAVING
  • la clausola ORDER BY (che nello snippet ho impostato a ProvinciaTable.NOME)

L’ oggetto restituito dalla query è Cursor (che ricorda il database handler del PHP): infatti nella Activity dovremo ciclare su di esso per estrarre le righe.
Vediamo come si estraggono i dati:

// siamo nella Activity principale
public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);
	// istanziamo l' helper della connessione
	DatabaseHelper databaseHelper = new DatabaseHelper(this);
	// eseguiamo la query
	Cursor c = databaseHelper.getProvince();

	try {
		while (c.moveToNext()) {
			Log.d("devAPP", c.getLong(0) + " " + c.getString(1) + " " + c.getString(2));
		}
	} finally {
		c.close();
	}
}

il codice è abbastanza semplice ed autoesplicativo.
Faccio solo notare i metodi moveToNext, getLong, e getString: il primo serve a muovere il cursore tra il recordset restituito dalla query (vedere la classe Cursor per altri metodi simili); gli altri due leggono i dati rispettivamente di tipo numerico (Long) e di tipo String.
Infatti la query viene eseguita sulle colonne ProvinciaTable.COLUMNS (vedere funzione getProvince()) che sono definite nell’ interfaccia (vedere all ‘inizio) ProvinciaTable come

String[] COLUMNS = new String[] {_ID, CODICE, NOME};

Conclusione

Al lancio dell’ applicazione viene istanziato il nostro DatabaseHelper, poi viene eseguita la query tramite databaseHelper.getProvince(): questa funzione chiama getReadableDatabase() che, se non trova il database, lo crea ex-novo, e lo fa chiamando il callback onCreate di DatabaseHelper.

Nella Activity ho usato la funzione Log.d(…) della classe Log: questa scrive nel log di Eclipse; per vederlo andare nel menu Window->Show View->Other e in “Android” selezionare Log Cat.

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...