Architecte Java/JEE @ Octo ! Archi, dev, audit, conseil ! [email protected] ! Développeur Android depuis 2009 ! Metroide ! Formateur Octo depuis 2010 ! Auteur de android-holo-colors.com ! Co-Inventeur de Appaloosa ! Co-Auteur de Robospice @jeromevdl +Jérôme Van Der Linden
Apache Harmony ! JavaSE 5 ! Et aussi ... ! Junit (3.8) ! Apache commons logging et HttpComponents ! Parsers json et xml ! Mais ... ! Toutes les méthodes des classe Android sont stubés ! throw new RuntimeException("Stub"); ! Impossible d’exécuter / tester sans émulateur / device Java
.class .dex .apk javac dx apkbuilber code bytecode application ! Compilation JIT depuis Android 2.2 ! Pas de génération de bytcode au runtime ! runtime weaving KO ! mais compiletime OK ! Des tentatives de groovy, scala ! GC mark&sweep https://sites.google.com/site/io/dalvik-vm-internals
! users, groups, droits... : par défaut l’utilisateur n’est pas root ! Sandboxing ! Une VM par application ! Un user unique par application ! Un process unique par application ! Un espace dédié du filesystem par application ! Permissions ! Un ensemble de permissions pour accéder aux différents services ! Les permissions sont affichées avant l’installation de l’application ! Signature ! Les applications sont signées pour être publiées sur le store ! Communications ! Les applications ne peuvent communiquer entre elles sauf ! Par des Intents ! Si elles utilisent un filesystem commun (ex: SDCard) ! Si elles autorisent explicitement dans le manifest (ContentProviders, Services ! Si elles ont la même signature (partage du même user id) Sécurité
static final class drawable { public static final int ic_dictionary=0x7f020000; public static final int ic_menu_search=0x7f020001; } public static final class layout { public static final int main=0x7f030000; public static final int result=0x7f030001; public static final int word=0x7f030002; } public static final class menu { public static final int options_menu=0x7f080000; } public static final class string { /** The name of the application. */ public static final int app_name=0x7f060000; /** The menu entry that invokes search. */ public static final int menu_search=0x7f060003; } public static final class id { public static final int list=0x7f090001; public static final int text=0x7f090000; } //... } Ressources R.java <resources> <!-- The name of the application. --> <string name="app_name">Dictionary</string> <!-- The menu entry that invokes search. --> <string name="menu_search">Search</string> </resources> strings.xml <TextView android:id="@+id/text" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <ListView android:id="@+id/list" android:layout_width="fill_parent" android:layout_height="0dp"> main.xml
java ! getResources.getDrawable (R.drawable.ic_menu_search) ! getResources.getString (R.string.menu_search) ! Et dans les xml ! @drawable/ic_dictionnary ! @string/menu_search ! @id/text Utilisation des ressources public final class R { public static final class drawable { public static final int ic_dictionary=0x7f020000; public static final int ic_menu_search=0x7f020001; } public static final class layout { public static final int main=0x7f030000; public static final int result=0x7f030001; public static final int word=0x7f030002; } public static final class menu { public static final int options_menu=0x7f080000; } public static final class string { /** The name of the application. */ public static final int app_name=0x7f060000; /** The menu entry that invokes search. */ public static final int menu_search=0x7f060003; } public static final class id { public static final int list=0x7f090001; public static final int text=0x7f090000; } //... } R.java
de l’IHM, conteneur d’éléments graphiques ! Généralement défini en XML à la XUL ! Et récupérable depuis Java : ! Ou instancié dynamiquement en java à la Swing ! Plus rare sauf pour vos propres composants Layout <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/button" android:text="@string/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> SuperExtendedButton button = new SuperExtendedButton(context); button.setText(R.string.button1); layout.addView(button); Button button = (Button) findViewById(R.id.button);
{ private String name; private int age; public int describeContents() { return 0; } public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeInt(age); } public User(Parcel userParcel) { name = userParcel.readString(); age = userParcel.readInt(); } public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() { public User createFromParcel(Parcel in) { return new User(in); } public User[] newArray(int size) { return new User[size]; } }; }
Via une action ! Exemple: partager du contenu ! Rendre son application réceptive à un Intent ! Via les intent-filter : action + category + data Intents – Navigation dans le système Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND); sharingIntent.setType("text/plain"); sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Subject Here"); sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, "Content to share"); startActivity(Intent.createChooser(sharingIntent, "Share via")); <activity android:name="ShareActivity" > <intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> <data android:mimeType="image/*" /> </intent-filter> </activity>
d’Adapters pour populer la liste ! Idem pour les Gridview ! listview.setAdapter(myAdapter); ! BaseAdapter, ArrayAdapter, CursorAdapter Listes <ListView android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" /> public class MyAdapter extends BaseAdapter { public int getCount() {} // return cell number public Object getItem(int position) {} // return model object for the cell public long getItemId(int position) {} // return cell object id (position) public View getView(int position, View convertView, ViewGroup parent) { View cell = null; if (convertView == null) { // create view by inflating layout for the cell here } else { cell = convertView; // recycle an older cell } // set cell attributes here return cell; } }
suivant : ! On peut extraire le style suivant : ! Et réduire ainsi le champ texte à : ! Mais surtout le rendre disponible à d’autres champs textes sans dupliquer des lignes et des lignes de propriétés Adoptez votre propre style <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" android:textColor="#00FF00" android:typeface="monospace" /> <resources> <style name="CodeFont" parent="@android:style/TextAppearance.Medium"> <item name="android:layout_width">fill_parent</item> <item name="android:layout_height">wrap_content</item> <item name="android:textColor">#00FF00</item> <item name="android:typeface">monospace</item> </style> </resources> <TextView style="@style/CodeFont" android:text="@string/hello" />
ensemble de styles appliqués à toute l’application ou à une activité entière ! Définition dans le fichier AndroidManifest.xml ! Depuis Honeycomb, Thème Holo (inspiré du film Tron) ! basé sur la couleur bleu #33b5e5 ! Pensez à étendre le style Holo ou Holo.Light pour vos thèmes Theme = ∑ styles <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@android:style/Theme.Holo.Light" > <activity android:name=".activity.SplashScreenActivity" android:theme="@android:style/Theme.NoTitleBar" /> <style name="CustomTheme" parent="android:Theme.Holo.Light"> <item name="android:windowBackground">@color/custom_theme_color</item> <item name="android:colorBackground">@color/custom_theme_color</item> </style>
! Création, compilation, debug, packaging ! Auto complétion dans le XML ! Editeur WYSIWYG ! DDMS, analyse des devices : ! thread, ! mémoire, ! filesystem, ! simulation d’appels, de SMS, de GPS, ... ! Logcat ! accès aux logs des devices Eclipse + ADT
de télécharger les différentes versions du SDK (SDK Manager) ! Permet de créer des projets Android ! Permet de créer des images AVD (Android Virtual Device) SDK Tools ! emulator ! Emule les images AVD ! Permet de tester/debugger l’application ! adb (Android Debug Bridge) ! Permet d’installer des apk (Android PacKage) sur le device ! Permet de copier des fichiers sur le device ! Permet d’exécuter des commandes shell sur le device
du code Android (~ PMD/Findbugs Android) ! Intégré à Eclipse et IntelliJ SDK Tools ! draw9patch ! Permet de créer des png « extensibles » ! Fichier « .9.png » ! traceview ! Profiling d’une application en cours d’exécution ! hierarchyviewer ! Permet de visualiser l’arbre des vues pour optimiser les perfs de l’UI
Android ! Injection de dépendances ! Injection de view... Librairies ! Spring Android ! RestTemplate pour faciliter les appels de services HTTP/REST ! Robospice ! Traitements réseaux asynchrones ! Mise en cache ! Ormlite ! ORM léger pour Sqlite
Mise à disposition des ActionBar sur les Android < 3.0 ! HoloEverywhere ! Mise à disposition du thème Holo pour les Android < 3.0 ! Android Asset Studio & Android Holo Colors ! Création d’icônes, d’images (holo), de fichiers de styles, ... ! Et des dizaines d’autres disponibles sur ! http://www.theultimateandroidlibrary.com/ ! http://www.openintents.org/en/libraries ! http://www.androidviews.net/
Privilégier quelque chose de plus léger : Roboguice ! Hibernate ? ! Idem : Ormlite ! Guava ? ! Pourquoi pas, même si la lib est un peu lourde ! Utiliser proguard pour réduire la taille du binaire final ! Apache Commons ? ! Absolument, ne réinventez pas la roue ! ! Jackson ! OK, évitez de parser les json à la main ! D’une manière générale ! Attention à la compatibilité avec le java d’Android ! Attention à la quantité et la taille des jars importés (dépendances transitives...) ! Vérifier qu’il n’y a pas un équivalent plus léger dédié à Android Et mes librairies Java ?
Basé sur JUnit ! Test d’Activités, de Services Android, ... ! Manipulation du Context ! Exécution sur un AVD ou un device ! Très lent ! ! UIAutomator ! Disponible à partir du SDK 16 ! Manipulation de l’interface avec des selector (à la CSS) ! monkey & monkeyrunner ! Test du singe : événements aléatoires sur l’interface Tests – Android
standard ! Pas besoin de device ou d’émulateur pour exécuter les tests ! Remplace les RuntimeException(stub) par des « Shadow Objects » Beaucoup plus rapide Tests – Robolectric @RunWith(RobolectricTestRunner.class) public class MyActivityTest { private Activity activity; private Button pressMeButton; private TextView results; @Before public void setUp() throws Exception { activity = new MyActivity(); activity.onCreate(null); pressMeButton = (Button) activity.findViewById(R.id.press_me_button); results = (TextView) activity.findViewById(R.id.results_text_view); } @Test public void shouldUpdateResultsWhenButtonIsClicked() throws Exception { pressMeButton.performClick(); String resultsText = results.getText().toString(); assertThat(resultsText, equalTo("Testing Android Rocks!")); } }
mock comme en Java ! Attention à Dalvik : Tous les frameworks ne sont pas compatibles ! Mockito ! Android Mock ! Easymock pas (encore) disponible ! En cours d’adaptation ! Android fournit également des classes de mock pour le contexte, les ressources, les contentprovider, ... Mocks
build initialement proposé par Google pour les projets Android ! build.xml automatiquement généré à la création d’un projet en ligne de commande (android create project ...) ! build.xml importe le build.xml fourni dans ${sdk.dir}/tools/ant/ ! Sauf besoins supplémentaires, il n’est pas nécessaire de définir des tâches de build ! Par défaut, couvre les besoins de compilation, packaging (release), déploiements sur un device/émulateur, test, coverage (emma) ! Est amené à disparaître... Build – Ant http://developer.android.com/tools/building/building-cmdline.html
package, test, deploie, execute, start/stop l’émulateur, obfusque, release, ... ! android.jar sur central depuis juin 2010 ! Ca n’a pas toujours été si simple... : mosabua ! De nombreux jar de librairies également sur central ! Ca n’a pas toujours été si simple... : mvn install:installl-file ! Intégration dans Eclipse avec m2eclipse (+ android connector) ! Ca n’a pas toujours été si simple... : m2eclipse-android-plugin ! Intégration native dans IntelliJ Build – Maven http://code.google.com/p/maven-android-plugin/ <plugin> <groupId>com.jayway.maven.plugins.android.generation2</groupId> <artifactId>android-maven-plugin</artifactId> <version>3.5</version> </plugin>
outil de build préconisé par Google, en remplacement de Ant ! Actuellement en version 0.1, pas stable et surtout pas accessible au commun des mortels (SDK previews) ! Un projet plus mature existe en attendant... ! https://github.com/jvoegele/gradle-android-plugin Build – Gradle http://tools.android.com/tech-docs/new-build-system/using-the-new-build-system
97% ! Oublier les versions < 2.2 ! 3 % du parc... tanpis pour eux ! Attention quand vous développez avec une version récente du SDK ! ! Code non dispo dans les SDK antérieurs Lint saura vous le rappeler ! Si besoin utiliser @TargetApi(API)! ! Et vérifier la valeur de android.os.Build.VERSION.SDK_INT! ! Utiliser la librairie de support ! android-support.jar ! Backport des fonctionnalités 3+ pour les versions >= 1.6 ! Fragments ! ViewPager ! Notifications ! ...
Des dizaines de résolutions différentes ! 320x240, 400x240, 640x240, 640x360, 480x320, 800x480, 854x480, 800x600, 960x540, 960x640, 1280x800, 1366x768… ! Densité (dp) ! Unité de mesure indépendante des pixels ! 1 dp = 1 pixel en mdpi ! px = dp * (dpi / 160) ! Utiliser les dp et sp, pas les px ! ! Oublier les small et ldpi ! 3% du parc ! La tendance est aux grands écrans 97% 3 4 6 8
tablette n’est pas nécessairement xlarge ! Il existe des tablettes 7’ large utiliser sw580dp à la place ! Adoptez les fragments ! Découpage de l’UI en « Fragments » ! Mutualisation des layouts entre smartphone et tablette
Disponible à partir du SDK 3 ! Utiliser ActionBarSherlock pour les versions antérieures ! Mixe automatique actionbar + menu contextuel sur les smartphones
l’UI ! Éviter d’instancier des objets dans les méthodes appelées des dizaines de fois par seconde (ex : onTouch, onScroll, onDraw...) ! Ne jamais faire de traitement long dans le thread UI ! Appels de webservices, requête complexe en bdd, decodage de bitmap, ... ! Utiliser des mécanismes pour faire des traitements asynchrones ! AsyncTask & AsyncTaskLoader ! Services ! Librairie Robospice (basée sur les services)
Android iOS WP7 ! Pas de bouton back ! Bouton physique ou dans l’ActionBar ! Pas d’indicateurs sur les lignes de liste ! Simplement rien ! Les onglets (Tab) sont en haut de l’écran ! Les icones des applications sont différentes (pas de halo, de carré arrondi) ! ...
Site de référence : très complet ! http://android-developers.blogspot.fr/ ! Blog officiel Google Android : annonces et bons articles ! http://www.androiduipatterns.com/ ! Blog sur les patterns UI et UX ! http://androiddevweekly.com/ ! Toutes les semaines, des articles, des libs, des exemples, des tutos... ! http://android.cyrilmottier.com/ ! Blog de Cyril Mottier, un expert Android reconnu ! Twitter : #android #androiddev ! Google+ : +AndroidDevelopers