Programação para a Plataforma Android Aula 11 Banco de Dados Introdução a linguagem SQL O banco de dados SQLite Como criar e manipular um banco de dados em Android Como apresentar dados na tela do aparelho celular Como criar um log simples de eventos Quais são as estruturas de dados mais comuns em Java?
SQLite Android disponibiliza um banco de dados chamado SQLite. SQLite é o banco de dados padrão em várias outras aplicações: Firefox, iphone, Symbia, Skype, etc. SQLite não possui licença, sendo de domínio público. Para usar SQLite, é preciso saber um pouco de SQL. Vocês lembram de alguma query?
Comandos de Definição Para criar uma tabela, podemos usar o comando abaixo: create table mytable ( _id integer primary key autoincrement, name text, phone text Qual o significado desse comando? ); E mais quais comandos nós temos em SQL?
Comandos de Modificação Para inserir algumas entradas em nosso banco de dados de exemplo, podemos usar os comandos abaixo: insert into mytable values(null, 'Steven King', '555 1212'); insert into mytable values(null, 'John Smith', '555 2345'); insert into mytable values(null, 'Fred Smitheizen', '555 4321'); Falta uma categoria de comandos
Comandos de Consulta O que fazem os seguintes comandos SQL? select * from mytable where(_id=3); select name, phone from mytable where(name like "%smith%");
Log de Eventos Logando Eventos Crie um banco de dados que logue eventos. Um evento possui um título e o tempo em que aconteceu. Eventos são criados via um método addevents(título).
EventsData.java O Banco de Dados import sta*c android.provider.basecolumns._id; import sta*c com.aula11.constants.table_name; import sta*c com.aula11.constants.time; import sta*c com.aula11.constants.title; public class EventsData extends SQLiteOpenHelper { private stahc final String DATABASE_NAME = "events.db"; private stahc final int DATABASE_VERSION = 1; public EventsData(Context ctx) { super(ctx, DATABASE_NAME, null, DATABASE_VERSION); } public void oncreate(sqlitedatabase db) { db.execsql("create TABLE " + TABLE_NAME + " (" + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + TIME + " INTEGER," + TITLE + " TEXT NOT NULL);"); } public void onupgrade(sqlitedatabase db, int oldversion, int newversion) { db.execsql("drop TABLE IF EXISTS " + TABLE_NAME); oncreate(db); } } Alguém sabe o que são essas importações estáticas? E o que faz esse comando SQL?
Constants.java Importações Estáhcas import android.provider.basecolumns; public interface Constants extends BaseColumns { final String TABLE_NAME = "events"; final String TIME = "hme"; final String TITLE = "htle"; } Precisamos de um layout para mostrar eventos.
main.xml Bom e Velho ScrollLayout <?xml version="1.0" encoding="u/ 8"?> <ScrollView xmlns:android="h5p://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:id="@+id/text" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </ScrollView> E como seria o programa principal?
O Programa Principal public class AulaAchvity11 extends Achvity { private EventsData events; @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); events = new EventsData(this); try { addevent("hello, Android!"); Cursor cursor = getevents(); showevents(cursor); } finally { events.close(); } } } AulaAchvity11.java Como ler esses eventos? E como mostrar esses eventos na tela? Como criar novos eventos?
Criando Eventos AulaAchvity11.java private void addevent(string string) { SQLiteDatabase db = events.getwritabledatabase(); ContentValues values = new ContentValues(); values.put(time, System.currentTimeMillis()); values.put(title, string); db.insertorthrow(table_name, null, values); } Qual é a semântica desse método? Ainda falta sermos capazes de ler eventos!
AulaAchvity11.java Lendo Eventos private stahc String[] FROM = { _ID, TIME, TITLE, }; private stahc String ORDER_BY = TIME + " DESC"; private Cursor getevents() { SQLiteDatabase db = events.getreadabledatabase(); Cursor cursor = db.query(table_name, FROM, null, null, null, null, ORDER_BY); startmanagingcursor(cursor); return cursor; } Qual deve ser a semântica de cada um desses argumentos? E o que deve ser um cursor? Quais métodos ele deve ter? E como mostrar todos os eventos logados na tela?
Mostrando Eventos na Tela AulaAchvity11.java private void showevents(cursor cursor) { StringBuilder builder = new StringBuilder( "Saved events:\n"); while (cursor.movetonext()) { long id = cursor.getlong(0); long hme = cursor.getlong(1); String htle = cursor.getstring(2); builder.append(id).append(": "); builder.append(hme).append(": "); builder.append(htle).append("\n"); } TextView text = (TextView) findviewbyid(r.id.text); text.settext(builder); } Vocês saberiam logar eventos de D-pad? E eventos de teclado? E que outros eventos?
public boolean onkeydown(int keycode, KeyEvent event) { switch (keycode) { case KeyEvent.KEYCODE_0: case KeyEvent.KEYCODE_1: case KeyEvent.KEYCODE_2: case KeyEvent.KEYCODE_3: case KeyEvent.KEYCODE_4: case KeyEvent.KEYCODE_5: case KeyEvent.KEYCODE_6: case KeyEvent.KEYCODE_7: case KeyEvent.KEYCODE_8: case KeyEvent.KEYCODE_9: addevent("number pressed"); Toast t1 = Toast.makeText(this, "Number pressed", Toast.LENGTH_SHORT); t1.setgravity(gravity.center, 0, 0); t1.show(); break; case KeyEvent.KEYCODE_SPACE: addevent("space pressed"); Toast t2 = Toast.makeText(this, "Space pressed", Toast.LENGTH_SHORT); t2.setgravity(gravity.center, 0, 0); t2.show(); break; default: return super.onkeydown(keycode, event); } showevents(getevents()); return true; } AulaAchvity11.java Outros Eventos
Associando Dados a Visões Android disponibiliza aos desenvolvedores alguns recursos gráficos para a exibição de tabelas. Compare, por exemplo: E como criar um layout como esse?
EventList.java import android.app.listachvity; ListAchvity public class EventList extends ListAchvity { private EventsData events; @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.evtlist); events = new EventsData(this); try { addevent("hello, Android!"); Cursor cursor = getevents(); showevents(cursor); } finally { events.close(); } } } Existe um layout próprio para listas. Listas são feitas para exibir itens de um banco de dados.
evtlist.xml Layout de Lista <?xml version="1.0" encoding="u 8"?> <LinearLayout xmlns:android="hƒp://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <! Veja os IDs built in de 'list' e 'empty' > <ListView android:id="@android:id/list" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <TextView android:id="@android:id/empty" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/empty" /> </LinearLayout> Agora é preciso alterar o método showevents para usar a lista, em vez da caixa de texto.
EventList.java Adaptadores import android.widget.simplecursoradapter; import stahc android.provider.basecolumns._id; private stahc String[] FROM = { _ID, TIME, TITLE, }; private stahc int[] TO = { R.id.rowid, R.id.hme, R.id.htle, }; private void showevents(cursor cursor) { SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.item, cursor, FROM, TO); setlistadapter(adapter); } Precisamos de um layout para cada item de lista.
<?xml version="1.0" encoding="u/ 8"?> <RelahveLayout xmlns:android="h5p://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientahon="horizontal" android:padding="10sp"> <TextView android:id="@+id/rowid" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/rowidcolon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=": " android:layout_torightof="@id/rowid" /> <TextView android:id="@+id/sme" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_torightof="@id/rowidcolon" /> <TextView android:id="@+id/smecolon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=": " android:layout_torightof="@id/sme" /> <TextView android:id="@+id/stle" android:layout_width="fill_parent" android:layout_height="wrap_content" android:ellipsize="end" android:singleline="true" android:layout_torightof="@id/smecolon" /> </RelahveLayout> item.xml Layouts Relahvos O que será exibido em cada linha da lista? O que é um layout relativo? E como deve ser o layout da lista em si?
evtlist.xml Built in IDs <?xml version="1.0" encoding="u 8"?> <LinearLayout xmlns:android="hƒp://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <ListView android:id="@android:id/list" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <TextView android:id="@android:id/empty" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/empty" /> </LinearLayout> Qual o papel da textview nesse layout? Onde esses IDs foram declarados? E onde foi declarada essa constante?
Strings strings.xml?xml version="1.0" encoding="u 8"?> <resources> <string name="app_name">events</string> <string name="empty">no events!</string> </resources>
addevents e getevents Esses métodos são os mesmos usados em nossa primeira implementação. private void addevent(string string) { EventList.java SQLiteDatabase db = events.getwritabledatabase(); ContentValues values = new ContentValues(); values.put(time, System.currentTimeMillis()); values.put(title, string); db.insertorthrow(table_name, null, values); } private stahc String ORDER_BY = TIME + " DESC"; private Cursor getevents() { SQLiteDatabase db = events.getreadabledatabase(); Cursor cursor = db.query(table_name, FROM, null, null, null, null, ORDER_BY); startmanagingcursor(cursor); return cursor; EventList.java }
ListView vs ScrollView A principal diferença das duas abordagens acontece no método showevents. ScrollView private void showevents(cursor cursor) { StringBuilder builder = new StringBuilder( "Saved events:\n"); while (cursor.movetonext()) { long id = cursor.getlong(0); long hme = cursor.getlong(1); String htle = cursor.getstring(2); builder.append(id).append(": "); builder.append(hme).append(": "); builder.append(htle).append("\n"); } TextView text = (TextView) findviewbyid(r.id.text); text.settext(builder); } ListView private void showevents(cursor cursor) { SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.item, cursor, FROM, TO); setlistadapter(adapter); }
Exercício: eventos de toque Modifique ListEvent para que essa ahvidade também trate eventos de toque. Esses eventos devem ser disparados na tela de ahvidade, mas não pela lista.
EventList.java Eventos de Toque @Override public boolean ontouchevent(mohonevent event) { if (event.getachon()!= MohonEvent.ACTION_DOWN) { addevent("touch Event!"); Toast t1 = Toast.makeText(this, "Touch!", Toast.LENGTH_SHORT); t1.setgravity(gravity.center, 0, 0); t1.show(); } showevents(getevents()); return true; }
Menu de Contexto Apagando itens Adicione um menu de contexto à lista, que dê ao usuário a opção de apagar um item da lista.
Registrando o menu @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.evtlist); events = new EventsData(this); registerforcontextmenu(getlistview()); try { addevent("hello, Android!"); Cursor cursor = getevents(); showevents(cursor); } finally { events.close(); } } EventList.java
Definindo o Menu private final int del = 0; @Override public final void oncreatecontextmenu (final ContextMenu menu, final View v, final ContextMenuInfo menuinfo) { super.oncreatecontextmenu(menu, v, menuinfo); menu.add(menu.none, del, Menu.NONE, "DEL"); } EventList.java
Tratando opções public final boolean oncontextitemselected(final MenuItem item) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getmenuinfo(); RelahveLayout rl = (RelahveLayout)info.targetView; TextView tv = (TextView)rl.getChildAt(0); String strid = tv.gettext().tostring(); switch (item.getitemid()) { case del: SQLiteDatabase db = events.getreadabledatabase(); db.delete(table_name, "_ID = " + strid, null); showevents(getevents()); break; } return true; } EventList.java
Adicionando mais opções Cancel É possível que o usuário mude de idéia ao clicar no item que precisa ser removido. Adicione uma opção CANCEL ao menu, que lhe permita retornar sem remover o item.
Cancel EventList.java private final int cancel = 1; @Override public final void oncreatecontextmenu(final ContextMenu menu, final View v, final ContextMenuInfo menuinfo) { super.oncreatecontextmenu(menu, v, menuinfo); menu.add(menu.none, del, Menu.NONE, "DEL"); menu.add(menu.none, cancel, Menu.NONE, "CANCEL"); } E como tratar a escolha do novo item?
public final boolean oncontextitemselected(final MenuItem item) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getmenuinfo(); RelahveLayout rl = (RelahveLayout)info.targetView; TextView tv = (TextView)rl.getChildAt(0); String strid = tv.gettext().tostring(); switch (item.getitemid()) { case del: SQLiteDatabase db = events.getreadabledatabase(); db.delete(table_name, "_ID = " + strid, null); showevents(getevents()); break; case cancel: break; } return true; } EventList.java
Lendo uma entrada específica Visualizando itens Adicione um terceiro item ao seu menu. Esse item, SHOW, deverá mostrar um item selecionado. Use a saída de Log para exibir informações sobre esse item.
EventList.java private final int show = 2; Nova opção @Override public final void oncreatecontextmenu(final ContextMenu menu, final View v, final ContextMenuInfo menuinfo) { super.oncreatecontextmenu(menu, v, menuinfo); menu.add(menu.none, del, Menu.NONE, "DEL"); menu.add(menu.none, show, Menu.NONE, "SHOW"); menu.add(menu.none, cancel, Menu.NONE, "CANCEL"); } Tratar esse evento não é trivial. Comece sendo capaz de selecionar o item.
Lendo um item específico public final boolean oncontextitemselected(final MenuItem item) { if (item.getitemid()!= cancel) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getmenuinfo(); RelahveLayout rl = (RelahveLayout) info.targetview; TextView tv = (TextView) rl.getchildat(0); String strid = tv.gettext().tostring(); SQLiteDatabase db = events.getreadabledatabase(); switch (item.getitemid()) { case del: db.delete(table_name, "_ID = " + strid, null); break; case show: Cursor cursor = db Mas, como ler os dados do cursor?.query(table_name, FROM, "_ID = " + strid, null, null, null, ORDER_BY); break; } showevents(getevents()); } return true; } EventList.java
EventList.java Manipulando o Cursor case show: Cursor cursor = db.query(table_name, FROM, "_ID = " + strid, null, null, null, ORDER_BY); Log.v("show", String.valueOf(cursor.getColumnCount())); Log.v("show", cursor.getcolumnname(0)); Log.v("show", cursor.getcolumnname(1)); Log.v("show", cursor.getcolumnname(2)); int hmecolumn = cursor.getcolumnindex(time); int htlecolumn = cursor.getcolumnindex(title); cursor.movetofirst(); String eventstr = cursor.getstring(htlecolumn); eventstr += "(" + cursor.getlong(hmecolumn) + ")"; Log.v("show", eventstr); break;
EventList.java Manipulando o Cursor case show: Cursor cursor = db.query(table_name, FROM, "_ID = " + strid, null, null, null, ORDER_BY); Log.v("show", String.valueOf(cursor.getColumnCount())); Log.v("show", cursor.getcolumnname(0)); Log.v("show", cursor.getcolumnname(1)); Log.v("show", cursor.getcolumnname(2)); int hmecolumn = cursor.getcolumnindex(time); int htlecolumn = cursor.getcolumnindex(title); cursor.movetofirst(); String eventstr = cursor.getstring(htlecolumn); eventstr += "(" + cursor.getlong(hmecolumn) + ")"; Log.v("show", eventstr); break;
EventList.java private stahc final int MAX_MENU_ID = 0; @Override public boolean oncreateophonsmenu(menu menu) { menu.add(menu.none, MAX_MENU_ID, Menu.NONE, "Get Oldest"); return true; } @Override public boolean onophonsitemselected(menuitem item) { switch (item.getitemid()) { case MAX_MENU_ID: AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setmessage("you have selected a menu!"); AlertDialog alert = builder.create(); alert.show(); return true; default: ; } return false; } O que esse código faz? Esse é um exemplo de um padrão de projetos. Qual? Modifique essa aplicação, para ela exibir na caixa o evento mais antigo.
Lendo o Evento mais Anhgo Comece criando um método getoldest, que retorna o evento mais antigo. Qual é a interface para esse método? Modifique essa aplicação, para ela exibir na caixa o evento mais antigo.
O Evento Mais Anhgo EventList.java private long getoldest(cursor c) { long oldesttime = 0L; int hmecolumn = c.getcolumnindex(time); Implemente for (c.movetofirst();!c.islast(); c.movetonext()) { algoritmo que leia o long currenttime = c.getlong(hmecolumn); evento mais antigo if (currenttime > oldesttime) { oldesttime = currenttime; dentre os eventos armazenados no } } cursor. return oldesttime; } E como incorporar esse código em seu menu?
Exibindo o Evento Mais Anhgo EventList.java @Override public boolean onophonsitemselected(menuitem item) { switch (item.getitemid()) { case MAX_MENU_ID: AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setmessage("oldest event = " + String.valueOf(getOldest(getEvents()))); AlertDialog alert = builder.create(); alert.show(); return true; default: ; } return false; }