Projet Android (LI260) Cours 4 Nicolas Baskiotis Université Pierre et Marie Curie (UPMC) Laboratoire d Informatique de Paris 6 (LIP6) S2-2013/2014
Résumé sur le multi-thread Service : facile opérations courtes bloque le thread principal doit lancer dans de nouveaux threads les opérations longues Thread : difficile générique pour toute opération à exécuter dans un autre thread IntentService : facile exécuté dans un thread parallèle une seule exécution à la fois, sans interaction avec les autres threads communication à l aide de message (pour la fin par exemple) ASyncTask : facile pour des opérations de durée moyenne (quelques secondes) exécuté dans un thread parallèle communication limitée avec l UI (progression) doit être créé par le thread principal
Plan
Opérations de stockage Options : Préférences : données primitives, légères, par clé-valeur Données privées : stockage interne ou externe, non partagée, détruites quand l application est désinstallée Données partagées : photos, images, sons en stockage externe Base de données : SQLite, accessible uniquement à l intérieur de l application Réseau : stockage en ligne
Préférences Caractéristiques : seulement type primitif (int, double, boolean,... ) persistant (même si l application est tuée) dans un seul fichier (Preferences) ou dans plusieurs fichiers (SharedPreferences) Utilisation lecture : (SharedPreferences getsharedpreferences(nom,0)).getint( myvar,defaut), écriture : un objet Editor (getsharedpreferences(nom,0).edit().putint( myvar,val)
Exemple p u b l i c class PreferenceDemo0 extends A c t i v i t y implements OnClickListener { Boolean fancyprefchosen = false ; final String MYPREFS = MyPreferences 001 ; SharedPreferences mysharedpreferences ; SharedPreferences. E d i t o r myeditor ; @Override public void oncreate ( Bundle savedinstancestate ) { super. oncreate ( savedinstancestate ) ;... mysharedpreferences = getsharedpreferences (MYPREFS, 0 ) ; myeditor = mysharedpreferences. edit ( ) ; i f ( mysharedpreferences!= null && mysharedpreferences. contains ( backcolor ) ) { applysavedpreferences ( ) ; else { Toast. maketext ( getapplicationcontext ( ), No Preferences found, 1 ). show ( ) ; p u b l i c void onclick ( View v ) { myeditor. c l e a r ( ) ; myeditor. putint ( backcolor, Color.BLACK ) ; / / black 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, bold ) ; / / fancy bold myeditor. p u t I n t ( l a y o u t C o l o r, Color.GREEN) ; / / fancy green myeditor. commit ( ) ; protected void onpause ( ) { myeditor. p u t S t r i n g ( DateLastExecution, 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 void applysavedpreferences ( ) { int backcolor = mysharedpreferences. getint ( backcolor, Color.BLACK ) ; int textsize = mysharedpreferences. getint ( textsize, 12); String textstyle = mysharedpreferences. getstring ( textstyle, normal ) ; int layoutcolor = mysharedpreferences. getint ( layoutcolor, Color.DKGRAY) ; String msg = color + backcolor + \n + size + textsize+ \n + style + textstyle ; Toast. maketext ( getapplicationcontext ( ), msg, 1 ). show ( ) ;
Base de données SQLite léger pour de petites bases, sans opérations intensives beaucoup de sucre syntaxique pour aider à la programmation soit accès direct avec toute la gestion des exceptions soit par l intermédiaire de l héritage En pratique, pour chaque table : classe SQLiteOpenHelper : gestion de la création et de la mise-à-jour (schéma) d une table de la bd une classe modèle : décrit l objet que l on stocke dans la table DAO : data access object, classe encapsulant les requêtes pour la manipulation des données
Opérations usuelles en pratique.execsql() : exécute une action SQL classe Cursor : curseur sur le résultat de requête : 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 modèle p u b l i c class Comment { private long id ; p r i v a t e S t r i n g comment ; public long getid ( ) { return id ; p u b l i c void s e t I d ( long i d ) { t h i s. i d = i d ; public String getcomment ( ) { r e t u r n comment ; p u b l i c void setcomment ( S t r i n g comment ) { t h i s. comment = comment ; / / W i l l be used by the ArrayAdapter i n the ListView @Override public String tostring ( ) { r e t u r n comment ;
Exemple : création p u b l i c class MySQLiteHelper extends SQLiteOpenHelper { public static final String TABLE COMMENTS = comments ; public s t a t i c f i n a l String 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 ; private static final String 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 statement 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 = create t a b l e + TABLE COMMENTS + ( + COLUMN ID + integer primary key autoincrement, + COLUMNCOMMENT + t e x t not n u l l ) ; ; public MySQLiteHelper ( Context context ) { super ( context, DATABASE NAME, null, DATABASE VERSION ) ; @Override public void oncreate ( SQLiteDatabase database ) { database. execsql (DATABASE CREATE ) ; @Override public void onupgrade ( SQLiteDatabase db, int oldversion, int newversion ) { Log.w( MySQLiteHelper. class. getname ( ), Upgrading database from version + oldversion + to + newversion +, which w i l l destroy all old data ) ; db. execsql ( DROP TABLE IF EXISTS + TABLE COMMENTS ) ; oncreate ( db ) ;
Exemple : DAO p u b l i c class CommentsDataSource { private SQLiteDatabase database ; p r i v a t e MySQLiteHelper dbhelper ; private String [ ] allcolumns = { MySQLiteHelper.COLUMN ID, MySQLiteHelper.COLUMNCOMMENT ; public CommentsDataSource ( Context context ) {dbhelper = new MySQLiteHelper ( context ); public void open ( ) throws SQLException {database = dbhelper. getwritabledatabase ( ) ; public void close ( ) {dbhelper. close ( ) ; p u b l i c Comment createcomment ( S t r i n g comment ) { ContentValues values = new ContentValues ( ) ; values. put ( MySQLiteHelper.COLUMNCOMMENT, comment ) ; long insertid = database. insert ( MySQLiteHelper.TABLE COMMENTS, null, values ) ; Cursor cursor = database. query ( MySQLiteHelper.TABLE COMMENTS, allcolumns, MySQLiteHelper.COLUMN ID + = + insertid, null, null, null, null ) ; cursor. movetofirst ( ) ; Comment newcomment = cursortocomment ( cursor ) ; cursor. close ( ) ; r e t u r n newcomment ;
Exemple : DAO p u b l i c void deletecomment (Comment comment ) { long id = comment. getid ( ) ; System. out. p r i n t l n ( Comment deleted with i d : + i d ) ; database. delete ( MySQLiteHelper.TABLE COMMENTS, MySQLiteHelper.COLUMN ID + = + id, null ) ; public List<Comment> getallcomments ( ) { L i s t<comment> comments = new A r r a y L i s t<comment>(); Cursor cursor = database. query ( MySQLiteHelper.TABLE COMMENTS, allcolumns, null, null, null, null, n u l l ) ; cursor. movetofirst ( ) ; while (! cursor. i s A f t e r L a s t ( ) ) { Comment comment = cursortocomment ( cursor ) ; comments. add (comment ) ; cursor. movetonext ( ) ; cursor. close ( ) ; r e t u r n comments ; p r i v a t e Comment cursortocomment ( Cursor cursor ) { Comment comment = new Comment ( ) ; comment. s e t I d ( cursor. getlong ( 0 ) ) ; comment. setcomment ( cursor. 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 class TestDatabaseActivity extends L i s t A c t i v i t y { p r i v a t e CommentsDataSource datasource ; public void oncreate ( Bundle savedinstancestate ) { super. oncreate ( savedinstancestate ) ; setcontentview (R. layout. main ) ; datasource = new CommentsDataSource ( this ) ; datasource. open ( ) ; L i s t<comment> values = datasource. getallcomments ( ) ; ArrayAdapter<Comment> adapter = new ArrayAdapter<Comment>(this, android.r. layout. s i m p l e l i s t i t e m 1, values ) ; s e t Li s t A d a p te r ( adapter ) ; public void onclick ( View view ) { ArrayAdapter<Comment> adapter = ( ArrayAdapter<Comment>) getlistadapter ( ) ; Comment comment = n u l l ; switch ( 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 nice, Hate i t ; i n t nextint = new Random ( ). nextint ( 3 ) ; comment = datasource. createcomment (comments [ n e x t I n t ] ) ; adapter. 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) getlistadapter ( ). getitem ( 0 ) ; datasource. deletecomment (comment ) ; adapter. remove (comment ) ; break ; adapter. notifydatasetchanged ( ) ; protected void onresume ( ) { datasource. open ( ) ; super.onresume ( ) ; protected void onpause ( ) { datasource. close ( ) ; super. onpause ( ) ;
Plan
MVC : Model-View-Control Objectif : séparer les données (model) l interface graphique (view) la manipulation (control) Opérations sur les vues properties : couleur, police, taille listeners : méthodes à l écoute des actions sur la vue focus visibilité
Exemples
Exemples
Mots-clés génériques 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 Héritage de BaseAdapter accepte un tableau d objet utilise la méthode tostring() de l objet utilise un TextView pour afficher chaque objet personnalisation pour afficher des objets plus complexes S t r i n g [ ] items = { Data 0, Data 1, Data 2, Data 3, Data 4, Data 5, Data 6, Data 7 ; ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.r. layout. s i m p l e l i s t i t e m 1, items ) ;
Exemple 1 XML Layout <LinearLayout xmlns : android= http : / / schemas. android.com / apk / res / android xmlns : tools= http : / / schemas. android.com / tools android : layout width= match parent android : layout height= match parent android : o r i e n t a t i o n = v e r t i c a l > <TextView android : id= @+id / txtmsg android : layout width= match parent android : l a y o u t h e i g h t = wrap content android : background= # f f f f f f 0 0 android : t e x t = Using ListViews... android : t e x t S i z e = 16sp /> <ListView android : i d = @+ i d / m y l i s t android : layout width= match parent android : layout height= match parent > </ListView> </LinearLayout>
Exemple 1 p u b l i c class ListViewDemo2 extends A c t i v i t y { S t r i n g [ ] items = { Data 0, Data 1, Data 2, Data 3, Data 4, Data 5, Data 6, Data 7 ; ListView mylistview ; TextView txtmsg ; @Override public void oncreate ( Bundle savedinstancestate ) { super. oncreate ( savedinstancestate ) ; setcontentview (R. layout. activity main ) ; mylistview = ( ListView ) findviewbyid (R. id. my list ) ; ArrayAdapter<String> aa = new ArrayAdapter<String>(this, android.r. layout. s i m p l e l i s t i t e m 1, items ) ; mylistview. setadapter (aa ) ; txtmsg = ( TextView ) findviewbyid (R. id. txtmsg ) ; mylistview. setonitemclicklistener (new OnItemClickListener ( ) { @Override public void onitemclick ( AdapterView<?> av, View v, i n t position, long i d ) { String t e x t = Position : + p o s i t i o n + \ndata : + items [ position ] ; txtmsg. settext ( text ) ; );
Exemple 2 Activity XML <?xml version= 1.0 encoding= UTF 8?> <LinearLayout xmlns : android= http : / / schemas. android.com / apk / res / android android : layout width= match parent android : l a y o u t h e i g h t = wrap content android : 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 android : padding= 2dp > <TextView android : id= @+id / txtmsg android : layout width= match parent android : l a y o u t h e i g h t = wrap content android : background= # f f 0 0 f f 0 0 android : t e x t = s c r o l l and c l i c k to s e l e c t... android : textappearance=? android : attr / textappearancelarge /> <H o r i z o n t a l S c r o l l V i e w android : layout width= match parent android : l a y o u t h e i g h t = wrap content android : background= #44aaaaaa > <LinearLayout android : id= @+id / 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 android : padding= 10 dip > </LinearLayout> </H o r i z o n t a l S c r o l l V i e w> <ImageView android : id= @+id / 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 android : l ay ou t w eig ht = 2 /> </LinearLayout>
Exemple 2 Icon Frame XML <?xml version= 1.0 encoding= UTF 8?> <LinearLayout xmlns : android= h t t p : / / schemas. android. com / apk / res / android android : layout width= 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 android : id= @+id / icon android : l a y o u t w i d t h = 80dp android : l a y o u t h e i g h t = 80dp android : paddingleft= 2dp android : paddingright= 2dp android : paddingtop= 2dp android : src= @drawable / i c l a u n c h e r /> <TextView android : i d = @+ i d / caption android : layout width= match parent android : l a y o u t h e i g h t = wrap content android : background= #55 ffff00 android : t e x t S i z e = 20sp /> </LinearLayout>
Exemple 2 p u b l i c class M a i n A c t i v i t y extends A c t i v i t y { TextView txtmsg ; ViewGroup scrollviewgroup ; ImageView icon ; TextView caption ; S t r i n g [ ] items = { Data 1,.. Integer [ ] thumbnails = { R. drawable. pic01 small,... Integer [ ] largeimages = { R. drawable. pic01 large,... ImageView imageselected ; protected void oncreate ( Bundle savedinstancestate ) { super. oncreate ( savedinstancestate ) ; setcontentview (R. layout. activity main ) ; txtmsg = ( TextView ) findviewbyid (R. id. txtmsg ) ; imageselected = ( ImageView ) findviewbyid (R. id. imageselected ) ; scrollviewgroup = ( ViewGroup ) findviewbyid (R. id. viewgroup ) ; f o r ( i n t i = 0; i < items. length ; i ++) { f i n a l View singleframe = getlayoutinflater ( ). i n f l a t e ( R. layout. frame icon caption, n u l l ) ; singleframe. s e t I d ( i ) ; TextView caption = ( TextView ) singleframe. findviewbyid (R. id. caption ) ; ImageView icon = ( ImageView ) singleframe. findviewbyid (R. id. icon ) ; icon. setimageresource ( thumbnails [ i ] ) ; caption. settext ( items [ i ] ) ; scrollviewgroup. addview ( singleframe ) ; singleframe. setonclicklistener (new View. OnClickListener ( ) { p u b l i c void onclick ( View v ) { S t r i n g t e x t = Selected p o s i t i o n : + singleframe. g e t I d ( ) ; txtmsg. settext ( text ) ; showlargeimage ( singleframe. g e t I d ( ) ) ; ); protected void showlargeimage ( int frameid ) { Drawable selectedlargeimage = getresources ( ). getdrawable ( largeimages [ frameid ] ) ; imageselected. setbackground ( selectedlargeimage ) ;