Banco de Dados

Propaganda
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;
}

Download