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 Para usar SQLite, público. é 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 Qu al o quais is a m E ); significa s nós do desse com ando? comando 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 Alguém sabe o que são essas importações estáticas? 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"; E o que faz esse private stahc final int DATABASE_VERSION = 1; comando SQL? 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); } } Importações Estáhcas Constants.java 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. Bom e Velho ScrollLayout main.xml <?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" eria o s o m o c E android:layout_width="fill_parent" ma a r g o r p android:layout_height="wrap_content" /> cipal? n i r p </ScrollView> O Programa Principal public class AulaAchvity11 extends Achvity { private EventsData events; @Override public void onCreate(Bundle savedInstanceState) { Como criar novos super.onCreate(savedInstanceState); eventos? setContentView(R.layout.main); events = new EventsData(this); Como ler try { esses addEvent("Hello, Android!"); eventos? Cursor cursor = getEvents(); showEvents(cursor); } finally { E como events.close(); mostrar } tos esses even } na tela? } AulaAchvity11.java 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? r E o que deve se 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()) { Vocês saberiam long id = cursor.getLong(0); logar eventos de long hme = cursor.getLong(1); D-pad? String htle = cursor.getString(2); E even builder.append(id).append(": "); tos de teclad builder.append(hme).append(": "); o? builder.append(htle).append("\n"); } ros t TextView text = (TextView) findViewById(R.id.text); u o que ? E text.setText(builder); tos n e v e } 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 r a para a exibição de i r c o E com out y tabelas. a l m u ? e s s mo e o c • Compare, por exemplo: EventList.java ListAchvity import android.app.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); out y a l m u } finally { e t Exis ra events.close(); próprio pa } 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"/> Agora é p <TextView alterar reciso o métod android:id="@android:id/empty" o showEv ents pa android:layout_width="wrap_content" ra usar a l i s ta, em v android:layout_height="wrap_content" ez da caix a d android:text="@string/empty" /> e texto. </LinearLayout> 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 é um layout relativo? O que será exibido em cada linha d a lista? 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" Qual o papel android:layout_height="fill_parent"> iew tV x te a d <ListView nesse layout? android:id="@android:id/list" android:layout_width="wrap_content" android:layout_height="wrap_content"/> Onde esses <TextView IDs foram android:id="@android:id/empty" declarados? android:layout_width="wrap_content" E onde foi android:layout_height="wrap_content" declarada android:text="@string/empty" /> essa </LinearLayout> 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 ListView 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); } 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. Eventos de Toque EventList.java @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. Nova opção EventList.java private final int show = 2; @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(); Mas, como ler SQLiteDatabase db = events.getReadableDatabase(); os dados do switch (item.getItemId()) { cursor? case del: db.delete(TABLE_NAME, "_ID = " + strId, null); break; case show: Cursor cursor = db .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 um for (c.moveToFirst(); !c.isLast(); c.moveToNext()) { algoritmo que leia o long currentTime = c.getLong(hmeColumn); evento mais antigo if (currentTime > oldestTime) { dentre os eventos oldestTime = currentTime; } armazenados no } cursor. return oldestTime; E como r esse ora p r o c n i } m seu e código 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; }