Armazenamento em Banco de Dados em Aplicações Android Prof. Fellipe Aleixo ([email protected]) Opções de Armazenamento • Shared Preferences – Armazenamento de pares chave-­‐valor • Internal Memory – UAliza a memória do aparelho • External Memory – UAliza algum armazenamento externo como cartão SD, USB, etc. • Banco de Dados SQLite • Mecanismo de banco de dados para o qual o Android oferece suporte naAvo • Obs.: banco de dados pode ser criados e acessados por qualquer classe de uma aplicação (apenas) O que é SQLite? • Trata-­‐se de uma biblioteca de soQware um motor de banco de dados SQL • CaracterísAcas: – Self-­‐contained – Serverless – Zero-­‐configura:on – Transac:onal – Open Source SQLite no Android • Nenhum banco de dados padrão é oferecido para a sua aplicação Android • A própria aplicação precisa criar o banco de dados, tabelas, índices e popular os dados SQLite no Android • Para criar e manipular banco de dados a maneira recomendada é criar uma subclasse de SQLiteOpenHelper e definir os métodos: – Construtor – onCreate() – onUpgrade() • Métodos opcionais: – onOpen() – onDowngrade() Construtor da Classe Helper • Exemplo: public class DicAonaryOpenHelper extends SQLiteOpenHelper { private staAc final String DATABASE_NAME = “meu_bd”; private staAc final int DATABASE_VERSION = 1; DicAonaryOpenHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } } – SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) Método onCreate() public class DicAonaryOpenHelper extends SQLiteOpenHelper { private staAc final String DATABASE_NAME = “meu_bd”; private staAc final int DATABASE_VERSION = 2; private staAc final String DICTIONARY_TABLE_CREATE = “CREATE TABLE DICTIONARY (KEYWORD TEXT,” + “ DEFINITION TEXT);”; DicAonaryOpenHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(DICTIONARY_TABLE_CREATE); } } Método onUpgrade() ... ... @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS DICTIONARY"); onCreate(db); } Uma vez criado o banco de dados, este pode ser acessado a parAr dos COMPONENTES GRÁFICOS Acessando o Banco de Dados package exemplo.aula; import android.app.AcAvity; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; public class HelloBDAcAvity extends AcAvity { private SQLiteDatabase database; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); DatabaseHelper helper = new DatabaseHelper(this); database = helper.getReadableDatabase(); } } Manipulando o Banco de Dados 1) UAlizar o método execSQL() – Para executar qualquer SQL que não retorna resultados (INSERT, UPDATE e DELETE) 2) UAlizar os métodos insert(), update() e delete() – Não é necessário trabalhar diretamente com SQL package exemplo.aula; import android.app.AcAvity; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; public class HelloBDAcAvity extends AcAvity { private SQLiteDatabase database; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); DatabaseHelper helper = new DatabaseHelper(this); database = helper.getWritebleDatabase(); database.execSQL("INSERT INTO DICTIONARY ”+ “(KEYWORD,DEFINITION) VALUES “+ “('Android','Plataforma para DisposiAvos Móveis')"); } } UAlizando Métodos Específicos • Não uAlizando SQL diretamente private void processAdd(DialogWrapper wrapper) { ContentValues values = new ContentValues(2); values.put(DatabaseHelper.TITLE, wrapper.getTitle()); values.put(DatabaseHelper.VALUE, wrapper.getValue()); db.getWritableDatabase().insert("constants", null, values); } private void processDelete(long rowId) { String[] args = { String.valueOf(rowId) }; db.getWritableDatabase().delete("constants", "ID=?", args); } Buscando Dados no Banco 1) Através do método rawQuery() – Permite a execução de um uma consulta SQL 2) Através do método query() – Não necessita trabalhar diretamente com SQL – São informados os critérios uAlizados na busca UAlizando o método rawQuery() • Informando a consulta SQL completa: database=db.getReadableDatabase(); Cursor constantsCursor; constantsCursor = database.rawQuery(“SELECT _ID, Atle, value “+ “FROM constants “+ “ORDER BY Atle", null); UAlizando o método query() • Parâmetros para compor a consulta: – O nome da tabela – A lista de colunas a serem retornadas – A cláusula WHERE (pode informar parâmetros) – Lista dos valores para subsAtuir os parâmetros – A cláusula GROUP BY – A cláusula HAVING – A cláusula ORDER BY UAlizando o método query() String[] columns={"ID", "inventory"}; String[] parms={"snicklefritz"}; Cursor result = db.query("widgets", columns, "name=?", parms, null, null, null); – Tabela “widgets” – Colunas desejadas: “ID” e “inventory” – WHERE name = ? – Parâmetro “snicklefritz” Manipulando Cursores • O resultado de uma consulta é um cursor – Apontador para os registros resultantes – Permite a navegação pelos resultados Manipulando Cursores • Métodos para manipulação de um cursor: – getCount() à número de registros retornados – Navegar pelos registros – moveToFirst(), moveToNext() e isAPerLast() – getColumnNames() e getColumnIndex() à recupera nomes e posição das culunas – requery() à reexecuta a consulta – close() à libera os recursos Manipulando Cursores Cursor result = db.rawQuery(“SELECT ID, name, inventory “+ “FROM widgets", null); while (!result.moveToNext()) { int id = result.getInt(0); String name = result.getString(1); int inventory = result.getInt(2); // Faz algo com os valores ... } result.close(); Vamos PRATICAR Construir uma Aplicação Exemplo • Aplicação: agenda de contatos – Um contato possui nome, e-­‐mail e telefone – Os contatos devem ser armazenados no banco Passo-­‐a-­‐Passo 1) Criar um projeto com o nome de “Contatos” – Pacote: exemplo.contatos – AAvidade: ContatosAcAvity 2) Criar uma classe com o nome “DbHelper” – Responsável por criar o banco de dados – Estende a classe SQLiteOpenHelper import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.uAl.Log; public class DbHelper extends SQLiteOpenHelper { ... } Passo-­‐a-­‐Passo 3) Definição de constantes private staAc final String DATABASE_NAME = “contatosDB”; private staAc final int DATABASE_VERSION = 1; public staAc final String TABLE_NAME = ”contatos”; public staAc final String ID = "_id"; public staAc final String NOME = "nome"; public staAc final String EMAIL = "email"; public staAc final String TELEFONE = "telefone"; public staAc final String FOTO = "foto"; private staAc final String DATABASE_CREATE = "create table “+ TABLE_NAME + “( “+ ID +" integer primary key autoincrement, " + NOME + " text not null, " + EMAIL + " text not null, ” + TELEFONE+" text not null, " + FOTO +" BLOB);"; Passo-­‐a-­‐Passo 4) Definição do construtor public DbHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } Passo-­‐a-­‐Passo 5) Definição dos métodos onCreate() e onUpgrade() @Override public void onCreate(SQLiteDatabase db) { db.execSQL(DATABASE_CREATE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVers, int newVers) { Log.w(DbHelper.class.getName(), "Upgrading database from “+oldVers+” to “+newVers); db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); onCreate(db); } Passo-­‐a-­‐Passo 6) Criar a classe DBAdpter para concentrar o trabalho com o banco de dados import java.io.ByteArrayOutputStream; import java.uAl.ArrayList; import java.uAl.List; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.SQLExcepAon; import android.database.sqlite.SQLiteDatabase; import android.graphics.Bitmap; import android.graphics.BitmapFactory; public class DBAdapter { ... } Passo-­‐a-­‐Passo 7) Declarar atributos e construtor da classe DBAdpter private SQLiteDatabase database; private DbHelper dbHelper; private String[] allColumns = { DbHelper.ID, DbHelper.NOME, DbHelper.EMAIL, DbHelper.TELEFONE, DbHelper.FOTO}; public DBAdapter(Context context) { dbHelper = new DbHelper(context); } Passo-­‐a-­‐Passo 8) Definir um método que insere um contato no banco de dados – Veja no próximo slide public Contacto createContacto(String nome, String email, String telefone, Bitmap foto) { ContentValues values = new ContentValues(); values.put(DB.NOME, nome); values.put(DB.EMAIL,email); values.put(DB.TELEFONE,telefone); ByteArrayOutputStream baos = new ByteArrayOutputStream(); foto.compress(Bitmap.CompressFormat.PNG, 100, baos); byte[] photo = baos.toByteArray(); values.put(DB.FOTO, photo); long insertId = database.insert(DB.TABLE_NAME, null, values); Cursor cursor = database.query(DB.TABLE_NAME, allColumns, DB.ID + " = " + insertId, null,null, null, null); cursor.moveToFirst(); return cursorToContato(cursor); } Passo-­‐a-­‐Passo 9) Criar uma classe Contato com os atributos, construtor com parâmetros e métodos acessadores e modificadores 10) Definir um método para remover um contato public void removeContato (int idContato) { database.delete(DbHelper.TABLE_NAME, DbHelper.ID + " = " + idContato, null); } Passo-­‐a-­‐Passo 11) Definir um método para retornar um contato passando um cursos para o mesmo private Contato cursorToContato(Cursor cursor) { byte[] blob = cursor.getBlob(cursor.getColumnIndex(DB.FOTO)); Bitmap bmp = BitmapFactory.decodeByteArray(blob, 0, blob.length); Contato contato = new Contato(cursor.getLong(0), cursor.getString(1), cursor.getString(2), cursor.getString(3), bmp); return contato; } Passo-­‐a-­‐Passo 12) Definir um método retornando os contatos public List<Contato> getContatos() { Cursor cursor = database.rawQuery("select * from contatos", null); ArrayList<Contato> contatos = new ArrayList<Contato>(); cursor.moveToFirst(); while(!cursor.moveToNext()) { Contato atual = new Contato(cursor.getLong(0), cursor.getString(1), cursor.getString(2), cursor.getString(3), bmp); contatos.add(atual); } return contatos; } Passo-­‐a-­‐Passo 13) Definir um método que retorna um contato passando o idenAficador do mesmo public Contato getContato (int idContato){ Cursor cursor = database.query(DB.TABLE_NAME, allColumns, DB.ID + " = " + idContato, null,null, null, null); cursor.moveToFirst(); return cursorToContato(cursor); } Passo-­‐a-­‐Passo 14) Crie as classes de Layout para operando com estas classes criada implemente a funcionalidade de agenda de contatos...