android-db

Activity, Database e ListView: come organizzare i nostri dati

Roberto Orgiu

Cosa siano i database e come usarli sono concetti che ormai molti hanno consolidato, magari utilizzando MySQL o Oracle DB, ma non tutti avranno una vasta esperienza di come utilizzarli sul nostro amato robottino verde e di come interagire con le ListView con layout personalizzato; magari ci sembra un qualcosa di difficile, ma in realtà non sono che poche righe di codice.

Per prima cosa, iniziamo a creare un layout apposito per il tipo di elementi che vogliamo mostrare, assegnando a ognuno degli elementi un ID, in modo che sia più o meno così:

e creiamo poi un altro file di layout per la tabella che vogliamo mostrare, utilizzando un LinearLayout con una ListView che riempia lo schermo (anch’essa con un id) utilizzando un codice XML simile a quello nel file visualizza.xml. Procediamo poi con la creazione dei due semplici layout: il main.xml che conterrà i due bottoni e inserisci.xml, che conterrà alcune Label, delle TextView e il bottone per il salvataggio.

Procediamo ora con il primo layout, in modo da vedere come lanciare una nuova Activity di nome InserisciActivity; iniziamo col dichiararla nel file Manifest:

<activity
 android:name=".InserisciActivity"
 android:label="@string/frmInserisciLabel"/>

dove android:label definisce il titolo che vogliamo che abbia la nostra schermata e continuiamo con il codice che serve per avviare la nostra Activity, utilizzando un Intent e l’apposita funzione:

Intent i1 = new Intent(this,InserisciActivity.class);
 startActivity(i1);

che andremo ad inserire nella gestione del click dell’apposito bottone e ripetiamo il procedimento per l’Activity di visualizzazione e il primo step della nostra applicazione è fatto.

Vediamo ora come gestire un database, creando una nuova classe che estenda SQLiteOpenHelper e che contenga nel metodo onCreate le istruzioni per creazione del nostro database (molto probabilmente questa classe sarà molto simile in tutte le nostre applicazioni, vista la sua semplicissima struttura)

public class DBHelper extends SQLiteOpenHelper{
public DBHelper(Context context, String name,
CursorFactory factory,int version) {
 super(context, name, factory, version);
 }
public void onCreate(SQLiteDatabase db) {
 db.execSQL(Script.CREATE_TABLE_PRODOTTI);
 }
@Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, 
int newVersion) {}
 }

l’unica istruzione utile in questo caso è db.execSQL(), che prende in ingresso una stringa che rappresenta il codice SQLite per la creazione delle nostre tabelle. A questo punto, procediamo con la stesura della classe Database, che si occuperà di gestire fisicamente la base di dati utilizzando la classe appena salvata, partendo dal costruttore

public Database(Context context){ 
helper = new DBHelper(context,Script.NOME_DB,
   null,Script.VERSIONE_DB);
db = helper.getWritableDatabase(); 
}

ora abbiamo ottenuto il nostro database e procediamo con la stesura dei metodi richiamabili per la chiusura, la cancellazione di un elemento e la selezione di tutti gli elementi della tabella.

public void close(){
db.close();
}
public void cancella(int id){
String[] args = {"" + id};
String where = Script.PRODOTTI_ID + "=?";
db.delete(Script.TABLE_PRODOTTI, where, args);
}
public Cursor ottieniProdotti(){
return db.query(Script.TABLE_PRODOTTI, null, null,
null, null, null, null);
}

Focalizziamoci sulla funzione db.delete (la db.query è analoga e funziona secondo lo stesso principio, con i parametri soliti della SELECT e le varie clausole aggiuntive) e notiamo i parametri where e args, che sono, rispettivamente, una stringa e un’array di stringhe: l’utilizzo è semplice, bisogna creare un parametro WHERE che contenga tanti caratteri ‘?‘ quanti sono i nostri argomenti (utilizzando le regole logiche) che verranno rimpiazzati dagli argomenti di args in ordine di apparizione.

Terminiamo questa classe con il metodo di inserzione, che si discosta leggermente dagli altri due, in quanto accetta come parametro un oggetto di tipo ContentValues, una sorta di mappa che contiene le associazioni di colonna-valore che vogliamo inserire in una data tabella

public void inserisciNuovo(String nome,int prezzo){
ContentValues cv = new ContentValues();
cv.put(Script.PRODOTTI_NOME, nome);
cv.put(Script.PRODOTTI_PREZZO, prezzo);
db.insert(Script.TABLE_PRODOTTI, null, cv);
}

Ecco finita la classe del database con metodi semplici ed intuitivi da richiamare e procediamo con il passo finale, colleghiamo i dati all’interfaccia, partendo dal passo più semplice, prelevare l’input da una TextView, che viene fatto molto facilmente con un codice analogo a questo:

EditText txtNome = (EditText)
findViewById(R.id.txtInserisciNome);
 String nome = txtNome.getText().toString();

A questo punto, siamo in grado di inserire le voci nel database, ma come fare per visualizzarle? Utilizziamo un SimpleCursorAdapter, che viene inizializzato con i valori del database e associa ad ogni riga il layout che abbiamo visto nell’immagine e alla tabella il codice XML che abbiamo scritto prima.

final Cursor c = d.ottieniProdotti();
 startManagingCursor(c);
 String from[] = {Script.PRODOTTI_NOME,
Script.PRODOTTI_PREZZO,Script.PRODOTTI_ID};
 int to[] = {R.id.txtElementoNome,R.id.txtElementoPrezzo,
         R.id.txtElementoId};
 SimpleCursorAdapter sca = new SimpleCursorAdapter(this,
         R.layout.elemento,c,from,to);

Come possiamo vedere, abbiamo due array (from e to) che associano le colonne della tabella agli elementi del layout; provvediamo ora a collegare il nostro layout alla ListView principale con queste istruzioni

ListView listaDb = (ListView) 
     findViewById(R.id.listViewElementi);
 listaDb.setAdapter(sca);

specificando che la lista deve essere cliccabile (in modo da poterci lavorare sopra)

listaDb.setClickable(true);

e affidiamo la gestione del tap/click ad un apposito listener, che ci permetterà di agire sull’elemento cliccato e ricaricare la nostra lista

listaDb.setOnItemClickListener
       (new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, 
          View v, int position, long id) {
 TextView txtId = (TextView) 
          v.findViewById(R.id.txtElementoId); 
 c.requery(); 
 }

L’ultima chiamata a funzione (c.requery()) è proprio quella che serve ad aggiornare la nostra lista dopo che abbiamo, ad esempio, cancellato un elemento.

Come al solito, potrete trovare tutti i link relativi a questo articolo nell’apposito thread del nostro forum, su cui potrete anche segnalarci eventuali difficoltà.