développer pour android - partie iii : activity, intents, sqlite, threads
TRANSCRIPT
Développer pour
Android
III – Activités
Les vues• Composant graphique élémentaire (boutons, images,
cases à cocher, etc.)
• Hérite de la classe View
• Vue = objet graphique
• Hiérarchisé dans des ViewGroup
• Le positionnement d’une vue dans l’activité se fait grâce à des gabarits => Layout
Les vues
• Labels TextView : typeface, textStyle, textColor
• Bouton Button : onClick = methode public avec un
parametre View
• Image ImageView / ImageButton : src, setImageURI()
• Champs de saisie EditText :
– autoText : correction auto de l’orthographe
– Capitalize : majuscule 1 lettre
– Digits : que des chiffres
– singleLine
• CheckBox / RadioButton : isChecked(), setChecked(),
toggle()
Les vues
• RadioGroup : groupe.check(R.id.radio1), clearCheck(),
getCheckedRadioButtonId()
• VideoView
• ProgressBar : barre de progression (horizontale, circulaire),
variante avec étoiles de notation avec RatingBar
• SeekBar : barre de réglage
• SearchView : champ de recherche avec proposition de
suggestions
• WebView
• …
• Vue customisé : www.androidviews.net
Miscellounous
• setEnabled() / isEnabled()
• requestFocus() / isFocused()
• getParent() : renvoie le widget ou le conteneur parent.
• findViewById() : permet de retrouver un widget fils d’après son
identifiant.
• getRootView() : renvoie la racine de l’arborescence (celle que
vous avez fournie à l’activité via un appel à setContentView()).
• Animate() : retourne un objet animateur pour lancer une
animation sur la vue
• LinearLayout : permet d’aligner de gauche à droite ou de haut en
bas les éléments qui y seront incorporés.
(orientation = horizontal / vertical)
• RelativeLayout : ses enfants sont positionnés les uns par rapport
aux autres, le premier enfant servant de référence aux autres
• FrameLayout : Ce gabarit est principalement utilisé pour l’affichage
d’un élément (par exemple, un cadre dans lequel on veut charger
des images)
• TableLayout : permet de positionner vos vues en lignes et
colonnes à l’instar d’un tableau.
• ScrollView / HorizontalScrollView : permet de défiler un contenu
trop grand pour tenir sur l’écran
Les Layout
• layout_alignParentTop: (true/flase) précise que le haut du widget
doit être aligné avec celui du conteneur.
• layout_alignParentBottom précise que le bas du widget doit être
aligné avec celui du conteneur.
• layout_alignParentLeft précise que le bord gauche du widget doit
être aligné avec le bord gauche du conteneur.
• layout_alignParentRight précise que le bord droit du widget doit
être aligné avec le bord droit du conteneur.
• layout_centerHorizontal précise que le widget doit être centré
horizontalement dans le conteneur.
• layout_centerVertical précise que le widget doit être centré
verticalement dans le conteneur.
• layout_centerInParent précise que le widget doit être centré
horizontalement et verticalement dans le conteneur.
RelativeLayout
• layout_above : (@id/vue) indique que le widget doit être placé au-dessus de celui
qui est désigné dans cette propriété.
• layout_below : indique que le widget doit être placé sous celui qui est désigné dans
cette propriété.
• layout_toLeftOf : indique que le widget doit être placé à gauche de celui qui est
désigné dans cette propriété.
• layout_toRightOf : indique que le widget doit être placé à droite de celui qui est
désigné dans cette propriété.
• layout_alignTop indique que le haut du widget doit être aligné avec le haut du
widget désigné dans cette propriété.
• layout_alignBottom indique que le bas du widget doit être aligné avec le bas du
widget désigné dans cette propriété.
• layout_alignLeft indique que le bord gauche du widget doit être aligné avec le bord
gauche du widget désigné dans cette propriété.
• layout_alignRight indique que le bord droit du widget doit être aligné avec le bord
droit du widget désigné dans cette propriété.
• layout_alignBaseline indique que les lignes de base des deux widgets doivent être
alignées.
RelativeLayout
TableLayout
• TableRow : conteneur de ligne
• layout_span : un widget pourra occuper plusieurs
cellules
• layout_column : le numéro de colonne où sera
placé le widget (0+)
Unités de mesure
• pixel (px) : correspond à un pixel de l’écran
• pouce (in) : unité de longueur, correspondant à 2,54 cm. Basé sur
la taille physique de l’écran
• millimètre (mm) : basé sur la taille physique de l’écran
• point (pt) : 1/7in
• pixel à densité indépendante (dp ou dip) : une unité relative se
basant sur une taille physique de l’écran de 160 dpi. Avec cette
unité, 1 dp est égal à 1 pixel sur un écran de 160 pixels. Si la taille
de l’écran est différente de 160 pixels, les vues s’adapteront selon
le ratio entre la taille en pixels de l’écran de l’utilisateur et la
référence des 160 pixels2 d’un pouce
• pixel à taille indépendante (sp) : fonctionne de la même manière
que les pixels à densité indépendante à l’exception qu’ils sont
aussi fonction de la taille de polices spécifiée par l’utilisateur. Il est
recommandé d’utiliser cette unité lorsque vous spécifiez les tailles
des polices.
Positionnement
• Dimension layout_width et layout_height (= Une dimension
précise, wrap_content, match_parent fill_parent)
• Poids layout_weight : proportion de l’occupation de l’espace
libre
• Gravité layout_gravity : l’alignement par rapport au
conteneur (= left, center_horizontal, center_vertical et right )
• Remplissage padding, paddingLeft, paddingRight,
paddingTop et paddingBottom.
Ressources• Référencement de chaque ressource par une constante
entière dans des classes internes de R.java
• Utilisation de Resources : Context.getResources() (Activity
hérite de Context) pour obtenir un getter de ressources
– getString(R.string.hello_world)
– getStringArray(R.stringarray.messages)
– getColor(R.color.my_nice_color)
– getLayout(R.layout.activity_layout)
– getDimension(R.dimen.world_width)
– getDrawable(R.drawable.card_picture)
– getIntArray(R.intArray.coordinates)
– openRawResource(R.raw.bindata) (retourne un InputStream)
– getIdentifier(nom,type, paquetage)
• Référencement d'une ressource au sein d'une autre
ressource par @[paquetage:]type/nomDeLaRessource
Ressources : versions
• Plusieurs versions d'une même ressource peuvent être
proposées dans des répertoire distincts suffixés par une
spécification de version :
– Langue et région : en, fr, fr-rCA
– Largeur d'écran : w<N>dp
– .Hauteur d'écran : h<N>dp
– Taille d'écran : parmi smal, normal, large et xlarge
– .Mode nuit : night, notnight
– Densité de l'écran : ldpi, mdpi, hdpi, xhdpi, nodpi, tvdpi
– Tactilité : notouch, finger, stylus
– Version de plate-forme : vN (e.g. v17 pour Android 4.2)
– …
ldpi = 75 x 60 px mdpi = 100 x 80 pxhdpi = 150 x 120 px hhdpi = 200 x 160 px
ldpi = mdpi x 0.75mdpi = résolution de référencehdpi = mdpi x 1.5xhdpi = mdpi x 2
Animation
• RotateAnimation
• ScaleAnimation
• TranslateAnimation
• AlphaAnimation
• AnimationUtils.loadAnimation
• setAnimation
VideoView videoview = (VideoView) findViewById(R.id.videoview);
Uri uri = Uri.parse("android.resource://"+getPackageName()+"/"+R.raw.nom_du_fichier);
videoview.setVideoURI(uri);
videoview.start();
Vidéo
public static void setImage(ImageView view, String url) throws IOException {
final URLConnection conn = new URL(url).openConnection();
conn.connect();
final InputStream is = conn.getInputStream();
final BufferedInputStream bis = new BufferedInputStream(is, 100000);
final Bitmap bm = BitmapFactory.decodeStream(bis);
bis.close();
is.close();
view.setImageBitmap(bm);
}
Image url
Music
• MediaPlayer :
– Ressource raw : create, start
– Fichier : setDataSource, prepare, start
• override onDestroy : stop, release
Polices
• typeFace : monospace, serif, sans …
• Font personnalisée TrueType : fichier ttf dans
sous dossier assets (assets/polices/)
• Chargement dans code java : – Typeface facePerso= Typeface.createFromAssets(getAssets(),
‘polices/mapolice.ttf’ );
txtViex.setFace(facePerso)
Menus
• Menu d’options : bouton menu– Item : Icon (72px haute res, 48px moy res 38px basse res), title,
enabled, titleCondensed, checked
– group : android:checkableBehavior="all | single«
– override boolean onCreateOptionsMenu (Menu menu) : 1 fois
– override boolean onPrepareOptionsMenu (Menu menu): chaque fois
– MenuInflater inflate() = deserialiser
– Reagir au click : boolean onOptionsItemSelected (MenuItem item) =>
item.getItemId()
– Creation dynamique : MenuItem add (int groupId, int objectId, int ordre, CharSequence titre)
MenuItem addSubMenu (int groupId, int objectId, int ordre, CharSequence titre)
• Menu.NONE
Menus
• Menu contextuel (longue pression)
– registerForContextMenu (View vue)
– Override : void onCreateContextMenu (ContextMenu menu, View vue,
ContextMenu.ContextMenuInfo menuInfo)
private int final static MENU_DESACTIVER = Menu.FIRST;private int final static MENU_RETOUR = Menu.FIRST + 1;
@Overridepublic void onCreateContextMenu(ContextMenu menu, View vue, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, vue, menuInfo);menu.add(Menu.NONE, MENU_DESACTIVER, Menu.NONE, "Supprimer cet élément");menu.add(Menu.NONE, MENU_RETOUR, Menu.NONE, "Retour");
}
Développer pour
Android
Les listes
Les listes
AdapterView
• ListView
• Spinner
• GridView
• AutoCompleteTextView
• Gallery
• StackView
DesignPattern MVC
DesignPattern Adapter
Les adapteurs
• ArrayAdapter<T> : pour tous les types de tableaux et list;
• BaseAdapter : pour créer des adaptateurs personnalisés ;
• CursorAdapter : pour traiter les données de type Cursor ;
• HeaderViewListAdapter : pour ajouter des entêtes et pieds de
page aux ListView ;
• ResourceCursorAdapter : pour la création de vues à partir d’une
disposition XML ;
• SimpleAdapter : malgré son nom, cet adaptateur s’emploie pour
des données complexes (from, to)
• SimpleCursorAdapter : sur-couche du CursorAdapter permettant
de lier un modèle XML aux données.
ArrayAdapter
• le contexte d’utilisation (généralement, il s’agit
de l’instance de l’activité)
• l’identifiant de ressource de la vue à utiliser
– Un identifiant d’une ressource système
android.R.layout.simple_list_item_1
– Un Layout personnalisé
• setAdapter() : attribuer l’adapteur à la liste
• setOnItemSelectedListener(AdapterView<?> parent, View view, int
position, long id))
• setChoiceMode() : CHOICE_MODE_SINGLE
CHOICE_MODE_MULTIPLE
Adapter personnalisé
• Hériter de la classe baseAdapter ou ArrayAdapter
• Redéfinir getView(int position, View convertView, ViewGroup parent)
• Si c’est le premier appel (convertView est null) on charge le layout
personalisé
• Utiliser un Layout Inflater pour récupérer le Layout xml dans une vue– Récupérer le LayoutInflater du contexte :
• LayoutInflater.from(getContext(),
• (LayoutInflater) ctx.getSystemService(Service.LAYOUT_INFLATER_SERVICE);
– Utiliser la méthode inflate(layout, groupviewparent, attachToRoot ) avec attachToRoot à
false
(NB: la méthode inflate retourne la vue nouvellement crée uniquement si parent est null
ou attachToRoot est false)
• Récupérer les valeurs à l’aide de la position (getItem(position)) et mettre
à jour le contenue des vue de notre Layout
Les sources de données
• Fichier
– Assets | java.io
– BufferedReader data=new BufferedReader(new
InputStreamReader(getAssets().open("datafile.txt")));
• Fichier xml
– Parser DOM | XmlPullParser …
– XmlPullParser xmlparser=getResources().getXml(R.xml.datafile)
– getEventType() : END_DOCUMENT , START_TAG, END_TAG
– getName() ,nextText(), getAttributeValue(), getText()
• Base de données SQLite
• DataProvider
SQLite
• Hériter de SQLiteOpenHelper
• SQLiteDatabase :
– instance depuis getReadableDatabase() ou getWriteableDarabase()
– onCreate() pour créer la base
• ContentValues pour insert ou update
• Cursor pour lire les données : rawQuery et Query
• moveToFirst(), moveToNext(), isAfterLast()
Types de données
• INTEGER - signed integer, stored in 1, 2, 3, 4, 6, or 8 bytes
depending on the magnitude of the value
• REAL - a floating point value, 8-byte IEEE floating point
number.
• TEXT - text string, stored using the database encoding
(UTF-8, UTF-16BE or UTF-16LE).
• BLOB. The value is a blob of data, stored exactly as it was
input.
update( )• int update(String table, ContentValues values, String
whereClause, String[ ] whereArgs)
public void updateBookTitle(Integer bookId, String newTitle) {
ContentValues values = new ContentValues();
values.put("title" , newTitle);
myDatabase.update("tbl_books" , values ,
"id=?" , new String[ ] {bookId.toString() } );
}
insert( )• long insert(String table, String nullColumnHack,
ContentValues values)
import android.content.ContentValues;
ContentValues values = new ContentValues( );
values.put("firstname" , "J.K.");
values.put("lastname" , "Rowling");
long newAuthorID = myDatabase.insert("tbl_authors" , "" ,
values);
delete( )• int delete(String table, String whereClause, String[]
whereArgs)
public void deleteBook(Integer bookId) {
myDatabase.delete("tbl_books" , "id=?" ,
new String[ ] { bookId.toString( ) } ) ;
}
Queries
• Methode de la classe SQLiteDatabase qui execute une
requete sql sur la BD et return un objet Cursor
• Cursor c = mdb.query(p1,p2,p3,p4,p5,p6,p7)
– p1 ; nom de la table (String)
– p2 ; colonnes à retourner (yableau String)
– p3 ; clause WHERE (utilisernull pour tout, ? pour les
arguments)
– p4 ; vleurs des rguments ? Dela clause WHERE
– p5 ; GROUP BY ( null si pas de groupement) (String)
– p6 ; HAVING (null si no requise) (String)
– p7 ; ORDER BY (null pour l’ordre par defaut)(String)
– p8 ; LIMIT (null ) (String)
Exemple de requetes
• SQL - "SELECT * FROM ABC;"
SQLite - Cursor c = mdb.query(abc,null,null,null,null,null,null);
• SQL - "SELECT * FROM ABC WHERE C1=5"
SQLite - Cursor c = mdb.query(
abc,null,"c1=?" , new String[ ] {"5"},null,null,null);
• SQL – "SELECT title,id FROM BOOKS ORDER BY title ASC"
SQLite – String colsToReturn [ ]= {"title","id"};
String sortOrder = "title ASC";
Cursor c = mdb.query("books",colsToReturn,
null,null,null,null,sortOrder);
Développer pour
Android
Les Intents
Intent
• Les Intents permettent de gérer l'envoi et la réception de
messages afin de faire coopérer les applications.
• Le but des Intents est de déléguer une action à un autre
composant, une autre application ou une autre activité de
l'application courante.
• Intent explicites : classe java ciblée
– Intent i = new Intent(this, ActivityTwo.class);
• Intent Implicites : une action + une donnée optionnel ( uri )
– Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse("http://www.google.com"));
– Uri : content://contacts/people/1 | geo:lat,long | tel:XXXX
Intent : données
• Intent.putExtra() :ajouter des données supplémentaires :– Clé (String) =>valeur (types primitifs (int, float,..), String, Bundle, Parceable et Serializable)
• L’activité appelée peut connaitre l’intent appelant getIntent() l’action de l’intent
getAction(), la donnée (uri) getData() et les données extras getExtras()
– Bundle extras = getIntent().getExtras();
– String valeur = extras.getString("clé_envoyée");
• Lancer l’activité :
– startActivity(intent) : appel d’une activité qui peut être externe à l’application
– startActivityForResult(intent, coderesultat) : appel une sous activité et reste en
attente de résultat :
• La sous activité peut retourner un code de résultat : setResult(coderesultat)
avant le finish() (par défaut on a RESULT_OK; RESULT_CANCELED,)
• La sous activité peut retourner des données supplémentaires sous forme
d’intent
• Une fois la Sous-activité terminée (finished), la méthode onActivityResult()est
appelée par l’activité mère
//Classe appelante
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
if (resultCode == RESULT_OK && requestCode == REQUEST_CODE) {
if (data.hasExtra("clé_retour1")) {
Toast.makeText(this,
data.getExtras().getString("clé_retour1"),
Toast.LENGTH_SHORT).show();
}
}
}
//Classe appelée
@Override
public void finish() {
Intent data = new Intent();
data.putExtra("clé_retour1", "Nom ");
data.putExtra("clé_retour2", "Prénom");
setResult(RESULT_OK, data);
super.finish();
}
Intent : filtres• le système peut choisir le composant le mieux adapté au traitement
d’une action
• chaque application va pouvoir facilement "écouter" les Intents dont
elle a besoin
• Plusieurs niveaux de filtrage :
– action: identifie le nom de l'Intent. Pour éviter les collisions, il faut utiliser la
convention de nommage de Java
– category: permet de filtrer une catégorie d'action (DEFAULT, BROWSABLE, ...)
– data: filtre sur les données du message par exemple en utilisant android:host pour
filtrer un nom de domaine particulier ou android:scheme (la partie gauche de l’url)
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme= "http" android:host= "ordiciel.ma"/>
</intent-filter>
Développer pour
Android
Les Threads
Thread
• Thread Processus
• S’exécute dans un processus en parallèle à d’autres
Threads
• Classe hérite de la classe Thread ou implémente
l’interface Runnable
• Définir la méthode run()
• Appeler la méthode start() depuis l’objet de la classe
problématique
• L’activityManager impose un delai aux UIThread (5s)
• Les traitements long (io, calcul, connexion ..) doivent être
exécuté dans des threads séparés
• Seul le UIThread (MainThread) est capable de mettre à jour
l’interface, aucun autre thread n’en a le droit
Solutions
Envoie de messages entre les Threads et l’UIThread
• Créer un handler dans l’UIThread qui va traiter les messages reçus :
– Objet de la classe Handler
– Redefinir la methode handleMessage(Message msg)
• Dans les Thread d’exécution créer des message à partir du handler (en le passant
au constructeur ou en mettant la classe thread comme classe interne):
– Handler.obtainMessage()
– Envoyer le message avec .sendToTarget(); de l’objet Message ou
sendEmptyMessage(11) du Handler
• Un message contient un entier what un entier arg1 un entier arg2 et un objet
optionnel. Il peut porter un bundle de données extra avec la méthodes
setData(Bundle data);