Projet Android (LI260) Cours 4

Projet Android (LI260)
Cours 4
Nicolas Baskiotis
Universite´ Pierre et Marie Curie (UPMC)
Laboratoire d’Informatique de Paris 6 (LIP6)
S2 - 2013/2014
´
Resum
e´ sur le multi-thread
• Service : facile
• operations
´
courtes
• bloque le thread principal
´
⇒ doit lancer dans de nouveaux threads les operations
longues
• Thread : difficile
• gen
´ erique
´
• pour toute operation
´
´
a` executer
dans un autre thread
• IntentService : facile
• execut
´ e´ dans un thread parallele
`
• une seule execution
´
a` la fois, sans interaction avec les autres
threads
• communication a
` l’aide de message (pour la fin par exemple)
• ASyncTask : facile
• pour des operations
´
´ moyenne (quelques secondes)
de duree
• execut
´ e´ dans un thread parallele
`
• communication limitee
´ avec l’UI (progression)
• doit etre
ˆ
cre´ e´ par le thread principal
Plan
´
Operations
de stockage
Options :
• Pref
´ erences
´
´ primitives, leg
´ eres,
`
´
: donnees
par cle-valeur
• Donnees
´ privees
´ : stockage interne ou externe, non partagee,
´
´
´
´
detruites
quand l’application est desinstall
ee
• Donnees
´ partagees
´ : photos, images, sons en stockage externe
• Base de donnees
´ : SQLite, accessible uniquement a` l’interieur
´
de l’application
• Reseau
´
: stockage en ligne
´ erences
´
Pref
´
Caracteristiques
:
• seulement type primitif (int, double, boolean, . . . )
• persistant (meme
ˆ
´
si l’application est tuee)
• dans un seul fichier (Preferences)
• ou dans plusieurs fichiers (SharedPreferences)
Utilisation
• lecture :
(SharedPreferences
getSharedPreferences(NOM,0))
.getInt(‘‘myvar’’,defaut),
• ecriture
´
: un objet Editor
(getSharedPreferences(NOM,0).edit()
.putInt(‘‘myvar’’,val)
Exemple
p u b l i c c l a s s PreferenceDemo0 extends A c t i v i t y implements O n C l i c k L i s t e n e r {
Boolean fancyPrefChosen = f a l s e ;
f i n a l S t r i n g MYPREFS = ” MyPreferences 001 ” ;
SharedPreferences mySharedPreferences ;
SharedPreferences . E d i t o r myEditor ;
@Override
p u b l i c v o i d onCreate ( Bundle s a v e d I n s t a n c e S t a t e ) {
super . onCreate ( s a v e d I n s t a n c e S t a t e ) ;
...
mySharedPreferences = getSharedPreferences (MYPREFS, 0 ) ;
myEditor = mySharedPreferences . e d i t ( ) ;
i f ( mySharedPreferences ! = n u l l && mySharedPreferences . c o n t a i n s ( ” backColor ” ) ) {
applySavedPreferences ( ) ;
} else {
Toast . makeText ( g e t A p p l i c a t i o n C o n t e x t ( ) , ” No P r e f e r e n c e s found ” , 1 ) . show ( ) ;
}
}
p u b l i c v o i d o n C l i c k ( View v ) {
myEditor . c l e a r ( ) ;
myEditor . p u t I n t ( ” backColor ” , C o l o r . BLACK ) ; / / b l a c k background
myEditor . p u t I n t ( ” t e x t S i z e ” , 1 2 ) ;
myEditor . p u t S t r i n g ( ” t e x t S t y l e ” , ” b o l d ” ) ; / / f a n c y b o l d
myEditor . p u t I n t ( ” l a y o u t C o l o r ” , C o l o r .GREEN ) ; / / f a n c y green
myEditor . commit ( ) ;
}
p r o t e c t e d v o i d onPause ( ) {
myEditor . p u t S t r i n g ( ” D a t e L a s t E x e c u t i o n ” , new Date ( ) . t o L o c a l e S t r i n g ( ) ) ;
myEditor . commit ( ) ;
super . onPause ( ) ;
}
p u b l i c v o i d applySavedPreferences ( ) {
i n t backColor = mySharedPreferences . g e t I n t ( ” backColor ” , C o l o r . BLACK ) ;
i n t t e x t S i z e = mySharedPreferences . g e t I n t ( ” t e x t S i z e ” , 1 2 ) ;
S t r i n g t e x t S t y l e = mySharedPreferences . g e t S t r i n g ( ” t e x t S t y l e ” , ” normal ” ) ;
i n t l a y o u t C o l o r = mySharedPreferences . g e t I n t ( ” l a y o u t C o l o r ” , C o l o r .DKGRAY ) ;
S t r i n g msg = ” c o l o r ” + backColor + ”\n ” + ” s i z e ” + t e x t S i z e + ”\n ” + ” s t y l e ” + t e x t S t y l e ;
Toast . makeText ( g e t A p p l i c a t i o n C o n t e x t ( ) , msg , 1 ) . show ( ) ;
}
´
Base de donnees
SQLite
• leger
´
• pour de petites bases, sans operations
´
intensives
• beaucoup de sucre syntaxique pour aider a` la programmation
• soit acces
` direct avec toute la gestion des exceptions
• soit par l’intermediaire
´
´
de l’heritage
En pratique, pour chaque table :
• classe SQLiteOpenHelper : gestion de la creation
´
et de la
`
´
mise-a-jour
(schema)
d’une table de la bd
• une classe modele
` : decrit
´
l’objet que l’on stocke dans la table
• DAO : data access object, classe encapsulant les requetes
ˆ
pour
´
la manipulation des donnees
´
Operations
usuelles en pratique
• .execSQL() : execute
´
une action SQL
• classe Cursor : curseur sur le resultat
´
ˆ :
de requete
• isFirst(), isLast(), moveToFirst(), moveToNext(),
moveToLast()
• getString(int i), getInt(int i), getColumnName(),
getColumnCount()
• classe ContentValues : stocke des paires champs/valeurs
.put(key,val)
• modification :
• public long insert(String table, String
nullColumnHack, ContentValues values)
• public int update( String table, ContentValues
values, String whereClause, String[] whereArgs)
• public int delete( String table, String
whereClause, String[] whereArgs)
Exemple :
db.update( "tbl",
(new ContentValues()).put(‘‘name’’,‘‘Moi’’),
"recID > ? and recID < ?", {‘‘2’’, ‘‘7’’} )}
`
Exemple : le modele
p u b l i c c l a s s Comment {
p r i v a t e long i d ;
p r i v a t e S t r i n g comment ;
p u b l i c long getId ( ) {
return id ;
}
p u b l i c void s e t I d ( long i d ) {
this . id = id ;
}
p u b l i c S t r i n g getComment ( ) {
r e t u r n comment ;
}
p u b l i c v o i d setComment ( S t r i n g comment ) {
t h i s . comment = comment ;
}
/ / W i l l be used by t h e A r r a y A d a p t e r i n t h e L i s t V i e w
@Override
public String toString () {
r e t u r n comment ;
}
}
´
Exemple : creation
p u b l i c c l a s s MySQLiteHelper extends SQLiteOpenHelper {
p u b l i c s t a t i c f i n a l S t r i n g TABLE COMMENTS = ” comments ” ;
p u b l i c s t a t i c f i n a l S t r i n g COLUMN ID = ” i d ” ;
p u b l i c s t a t i c f i n a l S t r i n g COLUMN COMMENT = ” comment ” ;
p r i v a t e s t a t i c f i n a l S t r i n g DATABASE NAME = ” commments . db ” ;
p r i v a t e s t a t i c f i n a l i n t DATABASE VERSION = 1 ;
/ / Database c r e a t i o n s q l s t a t e m e n t
p r i v a t e s t a t i c f i n a l S t r i n g DATABASE CREATE = ” c r e a t e t a b l e ”
+ TABLE COMMENTS + ” ( ” + COLUMN ID
+ ” i n t e g e r p r i m a r y key autoincrement , ” + COLUMN COMMENT
+ ” t e x t not n u l l ) ; ” ;
p u b l i c MySQLiteHelper ( Context c o n t e x t ) {
super ( c o n t e x t , DATABASE NAME, n u l l , DATABASE VERSION ) ;
}
@Override
p u b l i c v o i d onCreate ( SQLiteDatabase database ) {
database . execSQL (DATABASE CREATE ) ;
}
@Override
p u b l i c v o i d onUpgrade ( SQLiteDatabase db , i n t o l d V e r s i o n , i n t newVersion ) {
Log . w( MySQLiteHelper . c l a s s . getName ( ) ,
” Upgrading database from v e r s i o n ” + o l d V e r s i o n + ” t o ”
+ newVersion + ” , which w i l l d e s t r o y a l l o l d data ” ) ;
db . execSQL ( ”DROP TABLE I F EXISTS ” + TABLE COMMENTS ) ;
onCreate ( db ) ;
}
}
Exemple : DAO
p u b l i c c l a s s CommentsDataSource {
p r i v a t e SQLiteDatabase database ;
p r i v a t e MySQLiteHelper dbHelper ;
p r i v a t e S t r i n g [ ] allColumns = { MySQLiteHelper . COLUMN ID , MySQLiteHelper .COLUMN COMMENT };
p u b l i c CommentsDataSource ( Context c o n t e x t ) {dbHelper = new MySQLiteHelper ( c o n t e x t ) ; }
p u b l i c v o i d open ( ) throws SQLException {database = dbHelper . g e t W r i t a b l e D a t a b a s e ( ) ; }
p u b l i c v o i d c l o s e ( ) {dbHelper . c l o s e ( ) ; }
p u b l i c Comment createComment ( S t r i n g comment ) {
ContentValues v a l u e s = new ContentValues ( ) ;
v a l u e s . p u t ( MySQLiteHelper .COLUMN COMMENT, comment ) ;
l o n g i n s e r t I d = database . i n s e r t ( MySQLiteHelper . TABLE COMMENTS, n u l l , v a l u e s ) ;
Cursor c u r s o r = database . query ( MySQLiteHelper . TABLE COMMENTS,
allColumns , MySQLiteHelper . COLUMN ID + ” = ” + i n s e r t I d , n u l l , n u l l , n u l l , n u l l ) ;
c u r s o r . moveToFirst ( ) ;
Comment newComment = cursorToComment ( c u r s o r ) ;
cursor . close ( ) ;
r e t u r n newComment ;
}
Exemple : DAO
p u b l i c v o i d deleteComment ( Comment comment ) {
l o n g i d = comment . g e t I d ( ) ;
System . o u t . p r i n t l n ( ” Comment d e l e t e d w i t h i d : ” + i d ) ;
database . d e l e t e ( MySQLiteHelper . TABLE COMMENTS, MySQLiteHelper . COLUMN ID + ” = ” + i d , n u l l ) ;
}
p u b l i c L i s t<Comment> getAllComments ( ) {
L i s t<Comment> comments = new A r r a y L i s t<Comment>();
Cursor c u r s o r = database . query ( MySQLiteHelper . TABLE COMMENTS,
allColumns , n u l l , n u l l , n u l l , n u l l , n u l l ) ;
c u r s o r . moveToFirst ( ) ;
while ( ! cursor . i s A f t e r L a s t ( ) ) {
Comment comment = cursorToComment ( c u r s o r ) ;
comments . add ( comment ) ;
c u r s o r . moveToNext ( ) ; }
cursor . close ( ) ;
r e t u r n comments ;
}
p r i v a t e Comment cursorToComment ( Cursor c u r s o r ) {
Comment comment = new Comment ( ) ;
comment . s e t I d ( c u r s o r . getLong ( 0 ) ) ;
comment . setComment ( c u r s o r . g e t S t r i n g ( 1 ) ) ;
r e t u r n comment ;
}
}
Exemple : classe principale
p u b l i c c l a s s T e s t D a t a b a s e A c t i v i t y extends L i s t A c t i v i t y {
p r i v a t e CommentsDataSource datasource ;
p u b l i c v o i d onCreate ( Bundle s a v e d I n s t a n c e S t a t e ) {
super . onCreate ( s a v e d I n s t a n c e S t a t e ) ;
setContentView (R . l a y o u t . main ) ;
datasource = new CommentsDataSource ( t h i s ) ;
datasource . open ( ) ;
L i s t<Comment> v a l u e s = datasource . getAllComments ( ) ;
ArrayAdapter<Comment> a d a p t e r = new ArrayAdapter<Comment>(t h i s ,
android .R. l a y o u t . s i m p l e l i s t i t e m 1 , values ) ;
s e t L i s t A d a p t e r ( adapter ) ;
}
p u b l i c v o i d o n C l i c k ( View view ) {
ArrayAdapter<Comment> a d a p t e r = ( ArrayAdapter<Comment>) g e t L i s t A d a p t e r ( ) ;
Comment comment = n u l l ;
s w i t c h ( view . g e t I d ( ) ) {
case R . i d . add :
S t r i n g [ ] comments = new S t r i n g [ ] { ” Cool ” , ” Very n i c e ” , ” Hate i t ” };
i n t n e x t I n t = new Random ( ) . n e x t I n t ( 3 ) ;
comment = datasource . createComment ( comments [ n e x t I n t ] ) ;
a d a p t e r . add ( comment ) ;
break ;
case R . i d . d e l e t e :
i f ( g e t L i s t A d a p t e r ( ) . getCount ( ) > 0 ) {
comment = ( Comment ) g e t L i s t A d a p t e r ( ) . g e t I t e m ( 0 ) ;
datasource . deleteComment ( comment ) ;
a d a p t e r . remove ( comment ) ;
}
break ;
}
a d a p t e r . notifyDataSetChanged ( ) ;
}
p r o t e c t e d v o i d onResume ( ) {
datasource . open ( ) ;
super . onResume ( ) ;
}
p r o t e c t e d v o i d onPause ( ) {
datasource . c l o s e ( ) ;
super . onPause ( ) ;
Plan
MVC : Model-View-Control
´
Objectif : separer
• les donnees
´ (model)
• l’interface graphique (view)
• la manipulation (control)
´
Operations
sur les vues
• properties : couleur, police, taille
• listeners : methodes
´
´
a` l’ecoute
des actions sur la vue
• focus
• visibilite´
Exemples
Exemples
´ gen
´ eriques
´
Mots-cles
• orientation : vertical, horizontal
• fill model : match parent, wrap contents
• weight : 0,1,2,. . .
• gravity, layout gravity : top, bottom, center
• padding, margin
• layout alignParent{Top,Bottom,Left,Right},
layout center{InParent,centerVertical,centerHorizontal}
• layout {above,below,toLeftOf,toRightOf}
• layout span
List Widgets
ArrayAdapter
• Heritage
´
de BaseAdapter
• accepte un tableau d’objet
• utilise la methode
´
toString() de l’objet
• utilise un TextView pour afficher chaque objet
• personnalisation pour afficher des objets plus complexes
S t r i n g [ ] i t e m s = { ” Data−0” , ” Data−1” ,
” Data−2” , ” Data−3” ,
” Data−4” , ” Data−5” ,
” Data−6” , ” Data−7” };}
ArrayAdapter<S t r i n g> a d a p t e r =
new ArrayAdapter<S t r i n g >(t h i s ,
a n d r o i d .R . l a y o u t . s i m p l e l i s t i t e m 1 ,
items ) ;
Exemple 1
XML Layout
<L i n e a r L a y o u t xmlns : a n d r o i d = ” h t t p : / / schemas . a n d r o i d . com / apk / r e s / a n d r o i d ”
xmlns : t o o l s = ” h t t p : / / schemas . a n d r o i d . com / t o o l s ”
a n d r o i d : l a y o u t w i d t h = ” match parent ”
a n d r o i d : l a y o u t h e i g h t = ” match parent ”
android : o r i e n t a t i o n = ” v e r t i c a l ” >
<TextView
a n d r o i d : i d = ”@+ i d / txtMsg ”
a n d r o i d : l a y o u t w i d t h = ” match parent ”
android : l a y o u t h e i g h t = ” wrap content ”
a n d r o i d : background= ” # f f f f f f 0 0 ”
a n d r o i d : t e x t = ” Using L i s t V i e w s . . . ”
a n d r o i d : t e x t S i z e = ” 16sp ” />
<L i s t V i e w
a n d r o i d : i d = ”@+ i d / m y l i s t ”
a n d r o i d : l a y o u t w i d t h = ” match parent ”
a n d r o i d : l a y o u t h e i g h t = ” match parent ” >
</L i s t V i e w>
</L i n e a r L a y o u t>
Exemple 1
p u b l i c c l a s s ListViewDemo2 extends A c t i v i t y {
S t r i n g [ ] i t e m s = { ” Data−0” , ” Data−1” , ” Data−2” , ” Data−3” ,
” Data−4” , ” Data−5” , ” Data−6” , ” Data−7” };
L i s t V i e w myListView ;
TextView txtMsg ;
@Override
p u b l i c v o i d onCreate ( Bundle s a v e d I n s t a n c e S t a t e ) {
super . onCreate ( s a v e d I n s t a n c e S t a t e ) ;
setContentView (R . l a y o u t . a c t i v i t y m a i n ) ;
myListView = ( L i s t V i e w ) f i n d V i e w B y I d (R . i d . m y l i s t ) ;
ArrayAdapter<S t r i n g> aa = new ArrayAdapter<S t r i n g >(t h i s ,
android .R. l a y o u t . s i m p l e l i s t i t e m 1 ,
items ) ;
myListView . s e t A d a p t e r ( aa ) ;
txtMsg = ( TextView ) f i n d V i e w B y I d (R . i d . txtMsg ) ;
}
myListView . s e t O n I t e m C l i c k L i s t e n e r ( new O n I t e m C l i c k L i s t e n e r ( ) {
@Override
p u b l i c v o i d o n I t e m C l i c k ( AdapterView<?> av , View v ,
i n t p o s i t i o n , long i d ) {
String text = ” Position : ” + position
+ ”\nData : ” + i t e m s [ p o s i t i o n ] ;
txtMsg . s e t T e x t ( t e x t ) ;
}
});
}
Exemple 2
Activity XML
<?xml v e r s i o n = ” 1 . 0 ” encoding= ” UTF−8”?>
<L i n e a r L a y o u t xmlns : a n d r o i d = ” h t t p : / / schemas . a n d r o i d . com / apk / r e s / a n d r o i d ”
a n d r o i d : l a y o u t w i d t h = ” match parent ”
android : l a y o u t h e i g h t = ” wrap content ”
a n d r o i d : background= ” # f f f f f f f f ”
android : o r i e n t a t i o n = ” v e r t i c a l ”
a n d r o i d : padding= ” 2dp ” >
<TextView
a n d r o i d : i d = ”@+ i d / txtMsg ”
a n d r o i d : l a y o u t w i d t h = ” match parent ”
android : l a y o u t h e i g h t = ” wrap content ”
a n d r o i d : background= ” # f f 0 0 f f 0 0 ”
a n d r o i d : t e x t = ” s c r o l l and c l i c k t o s e l e c t . . . ”
a n d r o i d : textAppearance = ” ? a n d r o i d : a t t r / textAppearanceLarge ” />
<H o r i z o n t a l S c r o l l V i e w
a n d r o i d : l a y o u t w i d t h = ” match parent ”
android : l a y o u t h e i g h t = ” wrap content ”
a n d r o i d : background= ” #44aaaaaa ” >
<L i n e a r L a y o u t
a n d r o i d : i d = ”@+ i d / viewgroup ”
android : l a y o u t w i d t h = ” wrap content ”
android : l a y o u t h e i g h t = ” wrap content ”
android : o r i e n t a t i o n = ” h o r i z o n t a l ”
a n d r o i d : padding= ” 10 d i p ” >
</L i n e a r L a y o u t>
</H o r i z o n t a l S c r o l l V i e w>
<ImageView
a n d r o i d : i d = ”@+ i d / imageSelected ”
android : l a y o u t w i d t h = ” wrap content ”
android : l a y o u t h e i g h t = ” wrap content ”
a n d r o i d : l a y o u t w e i g h t = ” 2 ” />
</L i n e a r L a y o u t>
Exemple 2
Icon Frame XML
<?xml v e r s i o n = ” 1 . 0 ” encoding= ” UTF−8”?>
<L i n e a r L a y o u t
xmlns : a n d r o i d = ” h t t p : / / schemas . a n d r o i d . com / apk / r e s / a n d r o i d ”
a n d r o i d : l a y o u t w i d t h = ” match parent ”
android : l a y o u t h e i g h t = ” wrap content ”
android : o r i e n t a t i o n = ” v e r t i c a l ” >
<ImageView
a n d r o i d : i d = ”@+ i d / i c o n ”
a n d r o i d : l a y o u t w i d t h = ” 80dp ”
a n d r o i d : l a y o u t h e i g h t = ” 80dp ”
a n d r o i d : p a d d i n g L e f t = ” 2dp ”
a n d r o i d : p a d d i n g R i g h t = ” 2dp ”
a n d r o i d : paddingTop= ” 2dp ”
a n d r o i d : s r c = ” @drawable / i c l a u n c h e r ” />
<TextView
a n d r o i d : i d = ”@+ i d / c a p t i o n ”
a n d r o i d : l a y o u t w i d t h = ” match parent ”
android : l a y o u t h e i g h t = ” wrap content ”
a n d r o i d : background= ” #55 f f f f 0 0 ”
a n d r o i d : t e x t S i z e = ” 20sp ” />
</L i n e a r L a y o u t>
Exemple 2
p u b l i c c l a s s M a i n A c t i v i t y extends A c t i v i t y {
TextView txtMsg ; ViewGroup s c r o l l V i e w g r o u p ;
ImageView i c o n ; TextView c a p t i o n ;
S t r i n g [ ] i t e m s = { ” Data−1” , . . }
I n t e g e r [ ] t h u m b n a i l s = { R . drawable . p i c 0 1 s m a l l , . . . }
I n t e g e r [ ] largeImages = { R . drawable . p i c 0 1 l a r g e , . . . }
ImageView imageSelected ;
p r o t e c t e d v o i d onCreate ( Bundle s a v e d I n s t a n c e S t a t e ) {
super . onCreate ( s a v e d I n s t a n c e S t a t e ) ;
setContentView (R . l a y o u t . a c t i v i t y m a i n ) ;
txtMsg = ( TextView ) f i n d V i e w B y I d (R . i d . txtMsg ) ;
imageSelected = ( ImageView ) f i n d V i e w B y I d (R. i d . imageSelected ) ;
s c r o l l V i e w g r o u p = ( ViewGroup ) f i n d V i e w B y I d (R . i d . viewgroup ) ;
f o r ( i n t i = 0 ; i < i t e m s . l e n g t h ; i ++) {
f i n a l View singleFrame = g e t L a y o u t I n f l a t e r ( ) . i n f l a t e (
R. l a y o u t . frame icon caption , n u l l ) ;
singleFrame . s e t I d ( i ) ;
TextView c a p t i o n = ( TextView ) singleFrame . f i n d V i e w B y I d (R. i d . c a p t i o n ) ;
ImageView i c o n = ( ImageView ) singleFrame . f i n d V i e w B y I d (R . i d . i c o n ) ;
i c o n . setImageResource ( t h u m b n a i l s [ i ] ) ;
caption . setText ( items [ i ] ) ;
s c r o l l V i e w g r o u p . addView ( singleFrame ) ;
singleFrame . s e t O n C l i c k L i s t e n e r ( new View . O n C l i c k L i s t e n e r ( ) {
p u b l i c v o i d o n C l i c k ( View v ) {
S t r i n g t e x t = ” S e l e c t e d p o s i t i o n : ” + singleFrame . g e t I d ( ) ;
txtMsg . s e t T e x t ( t e x t ) ;
showLargeImage ( singleFrame . g e t I d ( ) ) ;
}
});
}
}
p r o t e c t e d v o i d showLargeImage ( i n t f r a m e I d ) {
Drawable selectedLargeImage = getResources ( )
. getDrawable ( largeImages [ f r a m e I d ] ) ;
imageSelected . setBackground ( selectedLargeImage ) ;
}
}