Database local
Deseori avem nevoie de a stoca mai multe date pentru un utilizator. In acest sens, in Android avem la dispozitie o serie de functionalitati pentru a realiza acest lucru. Astazi vom folosi SQLite, care vine inclusa in sistemul de operare.
Unul dintre principalele principii ale bazelor de date SQL este schema: o declarație formală a modului în care este organizată baza de date. Schema este reflectată în instrucțiunile SQL pe care le folosești pentru a crea baza de date. Poate fi util să creezi o clasă însoțitoare, cunoscută sub numele de clasă contract, care specifică explicit structura schemei tale într-un mod sistematic și auto-documentat.
O clasă contract este un container pentru constante care definesc nume pentru URI-uri, tables și columns. Clasa contract îți permite să folosești aceleași constante în toate celelalte clase din același package. Acest lucru îți permite să modifici numele unei coloane într-un singur loc și să se propage în tot codul tău.
Un mod bun de a organiza o clasă contract este să pui definițiile care sunt globale pentru întreaga bază de date la nivelul root al clasei. Apoi să creezi o inner class pentru fiecare table. Fiecare inner class enumeră columns-urile table-ului corespunzător.
public final class FeedReaderContract {
// To prevent someone from accidentally instantiating the contract class,
// make the constructor private.
private FeedReaderContract() {}
/* Inner class that defines the table contents */
public static class FeedEntry implements BaseColumns {
public static final String TABLE_NAME = "entry";
public static final String COLUMN_NAME_TITLE = "title";
public static final String COLUMN_NAME_SUBTITLE = "subtitle";
}
}
Crearea unui database
După ce ai definit cum arată baza ta de date, ar trebui să implementezi metode care creează și întrețin baza de date și tabelele. Iată câteva instrucțiuni tipice care creează și șterg un tabel:
private static final String SQL_CREATE_ENTRIES =
"CREATE TABLE " + FeedEntry.TABLE_NAME + " (" +
FeedEntry._ID + " INTEGER PRIMARY KEY," +
FeedEntry.COLUMN_NAME_TITLE + " TEXT," +
FeedEntry.COLUMN_NAME_SUBTITLE + " TEXT)";
private static final String SQL_DELETE_ENTRIES =
"DROP TABLE IF EXISTS " + FeedEntry.TABLE_NAME;
La fel ca fișierele pe care le salvezi în memoria internă a dispozitivului, Android stochează baza ta de date în folderul privat al aplicației tale. Datele tale sunt securizate, deoarece în mod implicit această zonă nu este accesibilă altor aplicații sau utilizatorului.
Clasa SQLiteOpenHelper
conține un set util de API-uri pentru gestionarea bazei
tale de date. Când folosești această clasă pentru a obține referințe la baza ta
de date, sistemul efectuează operațiunile potențial de lungă durată de creare
și actualizare a bazei de date doar când este necesar și nu în timpul pornirii
aplicației. Tot ce trebuie să faci este să apelezi getWritableDatabase()
sau
getReadableDatabase()
.
Pentru a utiliza SQLiteOpenHelper
, creează o subclasă care suprascrie
metodele callback onCreate()
și onUpgrade()
. De asemenea, poți implementa
metodele onDowngrade()
sau onOpen()
, dar acestea nu sunt obligatorii.
public class FeedReaderDbHelper extends SQLiteOpenHelper {
// If you change the database schema, you must increment the database version.
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "FeedReader.db";
public FeedReaderDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_ENTRIES);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// This database is only a cache for online data, so its upgrade policy is
// to simply to discard the data and start over
db.execSQL(SQL_DELETE_ENTRIES);
onCreate(db);
}
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
onUpgrade(db, oldVersion, newVersion);
}
}
Pentru a accesa baza ta de date, instanțiază subclasa ta de SQLiteOpenHelper
:
FeedReaderDbHelper dbHelper = new FeedReaderDbHelper(getContext());
Introducerea de date
Inserează date în baza de date prin transmiterea unui obiect ContentValues
către metoda insert()
:
// Gets the data repository in write mode
SQLiteDatabase db = dbHelper.getWritableDatabase();
// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_TITLE, title);
values.put(FeedEntry.COLUMN_NAME_SUBTITLE, subtitle);
// Insert the new row, returning the primary key value of the new row
long newRowId = db.insert(FeedEntry.TABLE_NAME, null, values);
Citirea de date
Pentru a citi dintr-o bază de date, folosește metoda query()
, transmițându-i
criteriile tale de selecție și coloanele dorite. Metoda combină elemente din
insert()
și update()
, cu excepția faptului că lista de coloane definește
datele pe care vrei să le preiei (denumită "projection"), și nu datele de
inserat. Rezultatele interogării îți sunt returnate într-un obiect Cursor
.
SQLiteDatabase db = dbHelper.getReadableDatabase();
// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
BaseColumns._ID,
FeedEntry.COLUMN_NAME_TITLE,
FeedEntry.COLUMN_NAME_SUBTITLE
};
// Filter results WHERE "title" = 'My Title'
String selection = FeedEntry.COLUMN_NAME_TITLE + " = ?";
String[] selectionArgs = { "My Title" };
// How you want the results sorted in the resulting Cursor
String sortOrder =
FeedEntry.COLUMN_NAME_SUBTITLE + " DESC";
Cursor cursor = db.query(
FeedEntry.TABLE_NAME, // The table to query
projection, // The array of columns to return (pass null to get all)
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
sortOrder // The sort order
);
Stergerea datelor
Pentru a șterge rânduri dintr-un tabel, trebuie să furnizezi criterii de
selecție care identifică rândurile pentru metoda delete()
. Mecanismul
funcționează la fel ca argumentele de selecție pentru metoda query()
. Acesta
împarte specificația de selecție în clauza de selecție și argumentele de
selecție. Clauza definește coloanele care trebuie examinate și îți permite, de
asemenea, să combini teste pe coloane. Argumentele sunt valori de testat care
sunt legate în clauză. Deoarece rezultatul nu este tratat la fel ca o
instrucțiune SQL obișnuită, acesta este imun la injecția SQL.
// Define 'where' part of query.
String selection = FeedEntry.COLUMN_NAME_TITLE + " LIKE ?";
// Specify arguments in placeholder order.
String[] selectionArgs = { "MyTitle" };
// Issue SQL statement.
int deletedRows = db.delete(FeedEntry.TABLE_NAME, selection, selectionArgs);
Actualizarea datelor
Când trebuie să modifici un subset din valorile bazei tale de date, folosește
metoda update()
. Actualizarea tabelului combină sintaxa ContentValues
a
metodei insert()
cu sintaxa WHERE
a metodei delete()
.
SQLiteDatabase db = dbHelper.getWritableDatabase();
// New value for one column
String title = "MyNewTitle";
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_TITLE, title);
// Which row to update, based on the title
String selection = FeedEntry.COLUMN_NAME_TITLE + " LIKE ?";
String[] selectionArgs = { "MyOldTitle" };
int count = db.update(
FeedReaderDbHelper.FeedEntry.TABLE_NAME,
values,
selection,
selectionArgs);