SlideShare une entreprise Scribd logo
session sept 2014 Yann Caron (c) 2014 1
IN01
Programmation Android
07 – Techniques avancées
Yann Caron
session sept 2014 Yann Caron (c) 2014 2
Sommaire - Séance 07
 Programmation avancée
➔
Capteurs
➔
Optimisations
➔
Tests unitaires
➔
Concurrence
 IHM avancées
➔
Vues personnalisées
➔
Fragments
 Autres
➔
Stratégies et alternatives
➔
Jeux vidéo mobiles
session sept 2014 Yann Caron (c) 2014 3
IN01 – Séance 07
Programmation avancée
Capteurs
session sept 2014 Yann Caron (c) 2014 4
Généralités

La miniaturisation et l'industrialisation rendent
aujourd'hui accessibles des capteurs précis au
grand public

La majorité des appareils Android embarquent
au moins un accéléromètre, un gyroscope et
un magnétomètre

Les trois tiennent sur ce circuit :
session sept 2014 Yann Caron (c) 2014 5
Différents capteurs Android
TYPE_ACCELE
ROMETER
3 m/s2 Mesure de l'accélération
(gravité incluse)
[0] axe x [1] axe y [2]
axe z
TYPE_GYROS
COPE
3 Rad / s Mesure la rotation en termes
de vitesse autour de chaque
axe
[0] vitesse x
[1] vitesse y
[2] vitesse z
TYPE_LIGHT 1 Lux Mesure de la luminosité [0]valeur
TYPE_MAGNE
TIC_FIELD
3 µTesla Mesure du champ magnétique [0] axe x [1] axe y [2]
axe z
TYPE_ORIENT
ATION
3 degrés Mesure l'angle entre le nord
magnétique
[0] Azimut y / nord
[1] Rotation x (-
180,180)
[2] Rotation y (-90,90)
TYPE_PRESSU
RE
1 KPas Mesure la pression [0]valeur
TYPE_PROXIM
ITY
1 mètre Mesure la distance entre
l'appareil et un objet cible
[0]valeur
TYPE_TEMPER
ATURE
1 Celsius Mesure la température [0]valeur
session sept 2014 Yann Caron (c) 2014 6
Présence du capteur

On peut interdire (ou pas) l'utilisation de l'application
aux appareils qui ne possèdent pas un certain
capteur

Utile si votre application ne peut pas fonctionner
sans de façon correcte

Dans le manifest (toujours !!) :
<uses-feature
android:name="android.hardware.sensor.accelerometer"
android:required="true" />
session sept 2014 Yann Caron (c) 2014 7
Sensor Manager

Pour accéder aux senseurs, on appelle une
méthode de l'Activity qui renvoie un objet de
type SensorManager

On peut récupérer la liste des capteurs
disponibles sur l'appareil
SensorManager sensorManager =
(SensorManager)getSystemService(Context.SENSOR_SERVICE);
ArrayList<Sensor> liste = (ArrayList<Sensor>)
sensorManager.getSensorList(Sensor.TYPE_MAGNETIC_FIELD);
session sept 2014 Yann Caron (c) 2014 8
Obtenir une instance de capteur

On peut maintenant obtenir une instance du
capteur souhaité

Attention !! Si le capteur n'est pas disponible,
l'objet renvoie la valeur null. Si le capteur n'est
pas requis, il faut tester et gérer s'il est absent.
Sensor accelerometre =
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
session sept 2014 Yann Caron (c) 2014 9
Évènement

Les capteurs fonctionnent aussi sur un modèle
évènementiel
final SensorEventListener mSensorEventListener = new SensorEventListener() {
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Que faire en cas de changement de précision ?
}
public void onSensorChanged(SensorEvent sensorEvent) {
// Que faire en cas d'évènements sur le capteur ?
}
};
Si la précision
a changé
Si les valeurs
ont changé
session sept 2014 Yann Caron (c) 2014 10
Évènement

Attention, il est préférable d'enregistrer
l'évènement lorsque l'application est active et
de le désenregistrer lorsque celle-ci est inactive

Sinon, il continue de s'exécuter
@Override
protected void onResume() {
super.onResume();
mSensorManager.registerListener(mSensorEventListener, mAccelerometer,
SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(mSensorEventListener, mAccelerometer);
}
session sept 2014 Yann Caron (c) 2014 11
Évènement – Valeurs

L'évènement du capteur renvoie un tableau de
valeurs float

Leur nombre et leur signification varient selon
les capteurs (voir tableau précédent)
public void onSensorChanged(SensorEvent sensorEvent) {
float[] values = sensorEvent.values;
Log.d("Sensors", "Acceleration sur l'axe x : " + values[0]);
Log.d("Sensors", "Acceleration sur l'axe y : " + values[1]);
Log.d("Sensors", "Acceleration sur l'axe z : " + values[2]);
}
session sept 2014 Yann Caron (c) 2014 12
Rotation

Doit être calculée avec les valeurs de l'accéléromètre et du
magnétomètre combinées à l'aide de formules complexes

Deux méthodes existent pour faciliter ce calcul :
getRotationMatrix() et getOrientation()
float[] values = new float[3];
float[] R = new float[9];
SensorManager.getRotationMatrix(R, null,
accelerometreValues, magnetometreValues);
SensorManager.getOrientation(R, values);
Log.d("Sensors", "Rotation sur l'axe z : " + values[0]);
Log.d("Sensors", "Rotation sur l'axe x : " + values[1]);
Log.d("Sensors", "Rotation sur l'axe y : " + values[2]);
session sept 2014 Yann Caron (c) 2014 13
Quelques applications
session sept 2014 Yann Caron (c) 2014 14
IN01 – Séance 07
Programmation avancée
Optimisation
session sept 2014 Yann Caron (c) 2014 15
Optimisation sous Android

Pourquoi ??
➔
Pour de meilleures performances !!

Oui, mais pour qui ??
➔
Les applications de bas niveau (un compilateur de
langage comme Algoid par exemple ;-))
➔
Des applications gourmandes en ressources (les
jeux vidéo, les applications graphiques)
session sept 2014 Yann Caron (c) 2014 16
Règles – Les objets

Éviter de créer des objets non nécessaires

En règle générale, éviter de créer trop d'objets !
➔
Parce que la création d'objets c'est gourmand
➔
Et la destruction encore pire : la dalvikVM bloque tout
processus lors du GC (GC dit Stop the World)
➔
Préférer les StringBuffer aux concaténations de strings à
outrance
➔
Un tableau d'int est meilleur qu'un tableau d'integer
(utilisation des types primitifs)
session sept 2014 Yann Caron (c) 2014 17
Règles – Les listes

Un tableau est meilleur qu'une ArrayList, même
règle que précédemment sur les types primitifs

Une ArrayList est moins coûteuse à lire qu'une
LinkedList (création d'objets entry qui seront à
gérer par le GC)
session sept 2014 Yann Caron (c) 2014 18
Règles – Les boucles

Idéal :

Catastrophique :
int size = myArray.length);
for (int i = 0; i < size; i ++) {
}
La taille est évaluée à chaque itération
Map<Integer, String> myMap = new HashMap();
for (Entry<Integer, String> item : myMap.entrySet()) {
}
Un objet Entry<Key, Value> créé à chaque itération
session sept 2014 Yann Caron (c) 2014 19
Règles – Méthodes et variables

Préférer les méthodes statiques aux méthodes de classe,
si aucun attribut de la classe n'est nécessaire

Utiliser static final pour les constantes

Éviter les inner class, surtout si elles ne sont pas statiques

Éviter les getter et setter (antipattern)

Les float 2x plus lents que les int

Les double sont 2x plus gourmands en mémoire que les
float
session sept 2014 Yann Caron (c) 2014 20
Règles - Conclusion

Attention toutefois à ne pas abuser des règles
d'optimisation

Évaluer si l'application nécessite une optimisation

Toujours mettre en relation le gain de
performances (CPU/Mem) et la lisibilité du code

Car attention ! Ces règles dégradent la qualité du
code et donc la lisibilité et la réutilisabilité
session sept 2014 Yann Caron (c) 2014 21
Optimisation - Outils

Toujours mesurer les gains par des micro-benchmarks :

Et le JIT (Just In Time Compiler) ?

Profilers netbeans ou Eclipse sont nos amis

Résultat : Algoid Language aussi rapide que Python est
plus rapide que JavaScript sur Android :-) Pas mal pour
un langage seulement interprété force brute
long time = System.currentTimeMillis();
for (int i=0; i<1000000; i++) {
// le code à tester
}
long timeSpent = System.currentTimeMillis() - time;
System.out.println("Time spent " + timeSpent);
session sept 2014 Yann Caron (c) 2014 22
IN01 – Séance 07
Programmation avancée
Tests unitaires
session sept 2014 Yann Caron (c) 2014 23
Vue d'ensemble

Créer des tests unitaires pour tester des apps
Android, c'est possible

Ça fonctionne avec JUnit

On peut tester l'interface utilisateur
(manipulation)
session sept 2014 Yann Caron (c) 2014 24
Création du projet de test

Depuis
Eclipse
session sept 2014 Yann Caron (c) 2014 25
Création du projet de test

On choisit le
projet à tester
session sept 2014 Yann Caron (c) 2014 26
Test Fixture

Pour créer un test case, il suffit de créer une
nouvelle classe de test

Celle-ci devra hériter de la classe
ActivityInstrumentationTestCase2

Et fournir la classe à tester dans son constructeur
public class ActivityTest
extends ActivityInstrumentationTestCase2<MainActivity>{
public ActivityTest() {
super(MainActivity.class);
}
}
La Classe à tester
session sept 2014 Yann Caron (c) 2014 27
SetUp

Lors du setUp, on récupère les instances de
l'activity et des composants à tester
private MainActivity activity = null;
private TextView myTextView = null;
private Button myButton = null;
@Override
protected void setUp() throws Exception {
super.setUp();
activity = getActivity();
myTextView = (TextView) activity.findViewById(
fr.cnam.helloworld.R.id.myTextView);
myButton = (Button)activity.findViewById(
fr.cnam.helloworld.R.id.myButton);
}
R (ressources)
du projet à tester
session sept 2014 Yann Caron (c) 2014 28
Préconditions

Une bonne pratique consiste à tester que le
setUp s'est bien déroulé
@SmallTest
public void testPreconditions() {
assertNotNull("activity is null", activity);
assertNotNull("myTextView is null", myTextView);
assertNotNull("myButton is null", myButton);
}
session sept 2014 Yann Caron (c) 2014 29
Layout test

Tester le layout des composants
@MediumTest
public void testMyTextView_layout() {
final View decorView = activity.getWindow().getDecorView();
ViewAsserts.assertOnScreen(decorView, myTextView);
final ViewGroup.LayoutParams layoutParams =
myTextView.getLayoutParams();
assertNotNull(layoutParams);
assertEquals(layoutParams.width,
WindowManager.LayoutParams.WRAP_CONTENT);
assertEquals(layoutParams.height,
WindowManager.LayoutParams.WRAP_CONTENT);
}
Test que le composant
est présent
session sept 2014 Yann Caron (c) 2014 30
@MediumTest
public void testMyButton_click() {
String initialText = activity.getString(
fr.cnam.helloworld.R.string.hello_world);
String expectedText = activity.getString(
fr.cnam.helloworld.R.string.after_click);
assertEquals(initialText, myTextView.getText());
TouchUtils.clickView(this, myButton);
assertEquals(expectedText, myTextView.getText());
}
Tester les comportements souhaités

Utilisation de TouchUtils pour simuler les
actions utilisateur
Clic sur le bouton
session sept 2014 Yann Caron (c) 2014 31
Test Annotations

@SmallTest :
➔
Un test court, moins de 100 ms

@MediumTest :
➔
Un test de durée moyenne, supérieure à 100 ms

@LargeTest :
➔
Idem que le mediumTest, avec un accès plus
important aux ressources
session sept 2014 Yann Caron (c) 2014 32
Résultats

Et voilà le travail !!

Les sources complètes
sont dans le projet du
cours

Bons tests !!
session sept 2014 Yann Caron (c) 2014 33
IN01 – Séance 07
Programmation avancée
Concurrence
session sept 2014 Yann Caron (c) 2014 34
Généralités

Pour gérer des traitements et pour ne pas bloquer
l'interface utilisateur, on utilise des Threads

Problème !! Il nous est interdit de modifier l'IHM
depuis un autre Thread que le Thread principal

Deux outils existent sur Android : Handler et
AsyncTask

cf. SwingWorker de Swing
session sept 2014 Yann Caron (c) 2014 35
Handler - Pattern

Son but : synchroniser de petites tâches et les ordonner (comme un
ordonnanceur)

Un handler particulier attaché à l'IHM

C'est une queue de tâches

Le consommateur se met en attente sur la queue

Lorsqu'une tâche est ajoutée par un des multiples producteurs
(threads), la queue est notifiée, débloquant ainsi le consommateur

Lorsque le consommateur a tout consommé, il se remet en attente

Ça ressemble au patron Reader – Writer lock, mais, inversé (multiple
writer et mono reader)

Utilisation massive dans Algoid (le script emploie son propre thread)
session sept 2014 Yann Caron (c) 2014 36
Handler - Utilisation

Il faut créer un handler (ou en récupérer un
d'une vue)

Puis lui envoyer des tâches
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
}
});
session sept 2014 Yann Caron (c) 2014 37
Handler - Les méthodes

Plusieurs méthodes pour poster une tâche sont
disponibles :
➔
post() : place la tâche à la fin de la queue (sera exécutée
après toutes les autres)
➔
postAtFrontOfQueue() : place la tâche au début, juste
après celle en cours d'exécution
➔
postAtTime() : place la tâche avec un marqueur temps
➔
postDelayed() : place la tâche avec un marqueur de délai
session sept 2014 Yann Caron (c) 2014 38
AsyncTask

Utilisé pour des tâches généralement plus
longues

Et/ou, pour gérer l'affichage de la progression
dans l'IHM

On utilise la classe AsyncTask 
<TypeDesParamètres, 
TypeDeProgression, TypeDuRésultat>
session sept 2014 Yann Caron (c) 2014 39
AsyncTast - Création
class MyAsyncTask extends AsyncTask<String, Integer, String> {
@Override
protected String doInBackground(String... params) {
return null;
}
@Override
protected void onCancelled(String result) {
}
@Override
protected void onPostExecute(String result) {
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
}
Si la tâche est annulée
Tâche principale
Une fois finie
Gérer la progression
session sept 2014 Yann Caron (c) 2014 40
AsyncTask - Utilisation

Il suffit maintenant de l'instancier et de la
lancer

Les données seront transférées dans les
paramètres de la méthode
doInBackground(String... params)
MyAsyncTask task = new MyAsyncTask();
task.execute(new String[] { "my String" });
session sept 2014 Yann Caron (c) 2014 41
IN01 – Séance 07
IHM avancées
Vues personnalisées
session sept 2014 Yann Caron (c) 2014 42
Vue d'ensemble

Les Activities sont utilisées pour agréger des vues ensemble
(traitement d'un ensemble de données)

Une vue permet de traiter une donnée en particulier

Il existe quatre façons de créer des vues personnalisées :
➔
Une vue composée (héritage d'une sous-classe de ViewGroup)
➔
Un layout (héritage de ViewGroup)
➔
Spécialisation d'une vue existante (héritage d'une sous-classe de View)
➔
Création d'une vue de bout en bout (hérite de View)

Possibilité de combiner les approches
session sept 2014 Yann Caron (c) 2014 43
Vue composée

On doit créer une classe qui hérite d'une classe
elle-même héritant d'un viewGroup

Par exemple LinearLayout

Ensuite, dans le constructeur ou dans une
méthode spécifique, on ajoute dynamiquement
des vues enfants !!
session sept 2014 Yann Caron (c) 2014 44
Vue composée

Deux façons d'ajouter des composants :
➔
Par programmation grâce à la méthode addView (héritée de view)
➔
Par XML avec la méthode LayoutInflater
public class MyView extends LinearLayout {
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
EditText txt1 = new EditText(context);
EditText txt2 = new EditText(context);
super.addView(txt1);
super.addView(txt2);
}
}
session sept 2014 Yann Caron (c) 2014 45
Vue composée - Utilisation

Utile pour afficher des listes de données, des tableaux

Dans Algoid j'ai utilisé cette technique pour :
➔
Le File Manager

Construction dynamique de la vue en fonction des fichiers
➔
Invite de commande

Entrées sorties utilisateur pilotées par programme
➔
Scope View

Construction d'une vue hiérarchique en fonction de l'état de la
mémoire
session sept 2014 Yann Caron (c) 2014 46
Création d'un layout

Principe : hériter de la classe ViewGroup

Surcharger la méthode onLayout et placer les vues enfants
(getChildCount() et getChildAt())
public class MyLayout extends ViewGroup{
@Override
protected void onLayout(boolean changed, int l,
int t, int r, int b) {
for (int i = 0; i< getChildCount(); i++) {
View child = this.getChildAt(i);
child.setX(10);
child.setY(10 * i);
}
}
}
session sept 2014 Yann Caron (c) 2014 47
Spécialisation

Principe : hériter d'une vue existante (elle-même
spécialisation de la classe View)

Ajouter des comportements en surchargeant des
méthodes (il faut bien lire la documentation)

Ajouter des comportements sur des évènements
(onTouch, onLongClick,onKey)

Ajouter des dessins (surcharge de la méthode
onDraw)
session sept 2014 Yann Caron (c) 2014 48
Spécialisation – Exemple

L'IDE d'Algoid par exemple : AutoCompletion,
coloration syntaxique et breakpoints
public class SourceEditorTextView extends MultiAutoCompleteTextView {
public SourceEditorTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setOnLongClickListener(new OnLongClickListener() {
// ajouter les breakpoints
}
}
@Override
protected void onDraw(Canvas canvas) {
// dessiner ici les breakpoints
super.onDraw(canvas);
}
}
En réalité,
3 constructeurs
Ajoute un breakpoint
Dessine les breakpoints
session sept 2014 Yann Caron (c) 2014 49
Création de bout en bout

Principe : hériter de la classe View

Comme une vue spécialisée, mais sans
comportement préalable
➔
Gérer des évènements et implémenter les méthodes
nécessaires comme onDraw

Peut être long et fastidieux, il vaut mieux bien
évaluer si la vue n'existe pas au préalable

Exemple : Algo la petite tortue
session sept 2014 Yann Caron (c) 2014 50
Utilisation de la vue

Une fois la vue créée, il est possible de l'ajouter à un
conteneur :
➔
Activity, ViewGroup, Fragment

Toujours de deux façons :
➔
En Java
➔
En XML
addView(new MyView(context, attrs));
<fr.cnam.in01.techniques.MyView
android:id="@+id/myView"
myView:text1="myText1" myView:text2="myText2"/>
session sept 2014 Yann Caron (c) 2014 51
Paramètres personnalisés

Plusieurs étapes pour créer un attribut
personnalisé

But : pouvoir paramétrer la vue depuis des
valeurs passées dans l'XML

Un “Vrai” composant graphique !!
session sept 2014 Yann Caron (c) 2014 52
Paramètres personnalisés

Pour chaque attribut (ici text1 et text2), il faut
créer une paire getter/setter (setText1 etc.)

Il faut déclarer ces attributs dans une
ressource sous res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyView">
<attr name="text1" format="string" />
<attr name="text2" format="string" />
</declare-styleable>
</resources>
session sept 2014 Yann Caron (c) 2014 53
Paramètres personnalisés

Il faut ensuite déclarer le nouveau NameSpace
dans le fichier XML de l'activity (là où est
utilisé MyView)

Puis utiliser les paramètres dans la déclaration
du composant
xmlns:myview="http://schemas.android.com/apk/res-auto"
<fr.cnam.in01.techniques.MyView
android:id="@+id/myView"
myview:text1="myText one"
myview:text2="myText two"/>
session sept 2014 Yann Caron (c) 2014 54
Paramètres personnalisés

Et enfin, récupérer les valeurs dans le
constructeur de la vue
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedAttrs = getContext()
.obtainStyledAttributes(attrs, R.styleable.MyView);
String text1 = typedAttrs.getString(R.styleable.MyView_text1);
txt1.setText(text1);
String text2 = typedAttrs.getString(R.styleable.MyView_text2);
txt2.setText(text2);
}
session sept 2014 Yann Caron (c) 2014 55
Conclusion

De quoi créer des bibliothèques de
composants entièrement personnalisées

Idéal pour la réutilisabilité du code

Ou la distribution de celui-ci

Pourtant, encore assez peu de bibliothèques
graphiques ne sont disponibles sur Android !!
session sept 2014 Yann Caron (c) 2014 56
IN01 – Séance 07
IHM avancées
Fragments
session sept 2014 Yann Caron (c) 2014 57
Vue d'ensemble

Un fragment est un composant graphique qui se situe entre la vue et
l'activity

Il est lié à une activity

Il peut être graphique ou logique

Il peut être chargé/déchargé dynamiquement (par programmation)

Ou être utilisé de façon statique (en XML)

Il est disponible depuis la version 11 de l'API (HoneyComb), mais grâce à
l'app compat générée avec un projet Android, il peut être utilisé sur des
API plus anciennes

Il sert à adapter les interfaces aux différentes résolutions des appareils
session sept 2014 Yann Caron (c) 2014 58
Vue d'ensemble

Les activities peuvent être composées d'un ou plusieurs
fragments en fonction de la place à disposition
session sept 2014 Yann Caron (c) 2014 59
Cycle de vie

Il a son propre cycle de vie

Cela permet d'isoler son comportement et ainsi de rendre
plus “léger” le code de l'activity

onAttach : sert à récupérer l'instance de l'activity

onCreate : sert à instancier les objets non graphiques

onCreateView : idem, mais graphiques

onStart : lancer les traitements

onResume : s'abonner aux évènements, récupérer le contexte

onPause : s'y désabonner et sauver le contexte

onStop, onDestroyView, onDestroy, onDetach : on
désalloue les ressources créées ci-dessus
session sept 2014 Yann Caron (c) 2014 60
Création d'un fragment

Un fichier XML, comme pour une activity
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<!-- content -->
</LinearLayout>
session sept 2014 Yann Caron (c) 2014 61
Création d'un fragment

Et la classe associée (qui hérite de Fragment)

Laquelle implémente l'évènement onCreateView
public class MenuFragment extends Fragment
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.menu_fragment,
container, false);
return view;
}
session sept 2014 Yann Caron (c) 2014 62
layout/main_activity
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="fr.cnam.in01.in01_fragments.MainActivity"
tools:ignore="MergeRootFrame" >
<fragment
android:id="@+id/menu"
android:name="fr.cnam.in01.in01_fragments.MenuFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" />
</FrameLayout>
Un seul fragment
session sept 2014 Yann Caron (c) 2014 63
layout-land/main_activity
<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:orientation="horizontal">
<fragment
android:name="fr.cnam.in01.in01_fragments.MenuFragment"
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_weight="1" />
<fragment
android:name="fr.cnam.in01.in01_fragments.MainFragment"
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_weight="2" />
</LinearLayout>
Plusieurs fragments
session sept 2014 Yann Caron (c) 2014 64
Instance du fragment

Dans la méthode onLoad() de l'activity, on a
accès à l'instance du/des fragments

Attention, ils peuvent ne pas exister dans le
XML, leur référence est null dans ce cas !!

On utilise la méthode
Activity.getFragmentManager()
MenuFragment fragment = (MenuFragment) getFragmentManager()
.findFragmentById(R.id.menu);
session sept 2014 Yann Caron (c) 2014 65
Du fragment vers l'activity

Pour que les fragments soient réutilisables, il
ne faut pas qu'ils communiquent directement
avec l'activity

On utilise une inversion de dépendance

Par exemple un template method (design
pattern, peu utilisé dans les IHM)

Ou un observer/observable
session sept 2014 Yann Caron (c) 2014 66
Évènements

On définit une interface et un mécanisme d'évènement
public class MenuFragment extends Fragment {
private MenuChangeEvent menuChanged;
public interface MenuChangeEvent {
void menuChanger(int id);
}
public void setOnMenuChange(MenuChangeEvent menuChanged) {
this.menuChanged = menuChanged;
}
private void fireMenuChanged(int id) {
if (this.menuChanged != null) {
this.menuChanged.menuChanger(id);
}
}
Invertion de dépendance
Abonnement
session sept 2014 Yann Caron (c) 2014 67
Évènements

Dans l'activity, lorsque le fragment est chargé,
on s'abonne à l'évènement
menuFragment.setOnMenuChange(new MenuChangeEvent() {
@Override
public void menuChanger(int id) {
switch (id) {
case R.id.button1:
navigate(MenuFragment.class);
break;
case R.id.button2:
navigate(MainFragment.class);
break;
}
}
});
session sept 2014 Yann Caron (c) 2014 68
Placeholder

Les fragments peuvent être placés de façon
statique dans le XML, comme on l'a vu

Ils peuvent également être chargés
dynamiquement (par programmation) dans des
placeholders

En général, on utilise des FrameLayout
session sept 2014 Yann Caron (c) 2014 69
Placeholder
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<FrameLayout
android:id="@+id/placeholder1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<FrameLayout
android:id="@+id/placeholder2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2" />
</LinearLayout>
session sept 2014 Yann Caron (c) 2014 70
Placeholder

On peut ensuite, charger les fragments à l'aide d'un
objet de type FragmentTransaction

La méthode addToBackStack permet de gérer le
bouton back (conserve un historique des fragments
chargés, comme pour les activities)
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(placeholder, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(null);
ft.commit();
session sept 2014 Yann Caron (c) 2014 71
Navigation

Ensuite, selon le nombre de placeholder à disposition,
on choisit quel type de navigation l'on souhaite :
➔
Une seule, on peut lancer une nouvelle activity ou
remplacer le placeholder 1
➔
Deux, on peut choisir le placeholder à charger et remplacer
le précédent

Le mieux étant de toujours passer le nom de la classe
du fragment de façon à l'instancier par introspection
Class<? extends Fragment> frClass = MenuFragment.class;
Fragment fragment = frClass.newInstance();
session sept 2014 Yann Caron (c) 2014 72
Persistance des états du fragment

On l'a vu, les Fragments sont des objets autonomes avec leur
cycle de vie propre

L'idée initiale est de décharger l'activity des tâches propres aux
sous-éléments graphiques qui se chargent et se déchargent de
façon dynamique

De cette façon, il est possible de gérer la sauvegarde des états
dans un Bundle

Comme pour les activity, on utilise les évènements du cycle de
vie du fragment : onCreateView() et
onSaveInstanceState()
session sept 2014 Yann Caron (c) 2014 73
Menus

Les fragments apportent leur propre menu lorsqu'ils sont chargés
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.fragment_menu_item1:
// Action 1
return true;
default:
// Quelqu'un d'autre peut gérer ce menu
return super.onOptionsItemSelected(item);
}
}
session sept 2014 Yann Caron (c) 2014 74
Navigation drawer

Un menu qui glisse
quand on en a besoin

Source :
http://developer.android.
com/training/implement
ing-navigation/nav-
drawer.html
session sept 2014 Yann Caron (c) 2014 75
Navigation drawer

Création de l'activity
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ListView android:id="@+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"/>
</android.support.v4.widget.DrawerLayout>
Contenu
Menu sous forme
de liste
session sept 2014 Yann Caron (c) 2014 76
Navigation drawer

Chargement du menu dans l'activity
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView menu = (ListView) findViewById(R.id.menu);
String[] menuItems = getResources().getStringArray(R.array.menu_items_array);
// Set the adapter for the list view
menu.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, menuItems));
// Set the list's click listener
menu.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// TODO Auto-generated method stub
}
});
}
Items dans des tableaux
res/values
Gestion des événements
Icône + texte
session sept 2014 Yann Caron (c) 2014 77
Navigation drawer

Idéal avec les fragments

Google fournit un ensemble d'icônes

http://developer.android.com/downloads/desi
gn/Android_Design_Icons_20130926.zip
session sept 2014 Yann Caron (c) 2014 78
Navigation drawer
session sept 2014 Yann Caron (c) 2014 79
Conclusion

Les fragments offrent une réelle souplesse dans
l'organisation des IHM en fonction des résolutions

Une bonne pratique consiste à toujours concevoir ses
IHM selon des fragments, même pour des apps ne
nécessitant que peu d'écran

Une navigation plus riche pourra être conçue par la suite

Les composants de l'application bénéficieront également
d'une plus grande réutilisabilité
session sept 2014 Yann Caron (c) 2014 80
IN01 – Séance 07
Autres
Stratégies et alternatives
session sept 2014 Yann Caron (c) 2014 81
Stratégie – Choix de l'application

Red Ocean Strategy :
➔
Compléter un marché existant
➔
Exploiter une demande existante
➔
Battre la concurrence

Exemples : Pet rescue, Points and clicks

Avantage : Le marché existe déjà

Inconvénient : Pas d'innovation, pas passionnant
session sept 2014 Yann Caron (c) 2014 82
Stratégie – Choix de l'application

Blue Ocean Strategy :
➔
Créer un marché inexploité
➔
Créer ou capter de nouveaux besoins
➔
Pas de concurrence

Exemple : AIDE

Avantages : Avoir une longueur d'avance, être innovant,
développement motivant

Difficultés : Identifier le besoin, faire connaitre son
application
session sept 2014 Yann Caron (c) 2014 83
Dégager du revenu

Android une plateforme où il est difficile de
dégager du revenu
session sept 2014 Yann Caron (c) 2014 84
Enjeux du multiplateforme

De plus, il existe beaucoup d'applications sur le
Play Store (phénomène de flooding, noyade)

Les utilisateurs n'ont pas l'habitude d'acheter
sur cette plateforme

Il vaut mieux viser la publicité

Une meilleure stratégie consiste à viser
plusieurs plateformes
session sept 2014 Yann Caron (c) 2014 85
Enjeux du multiplateforme

Double avantage :
➔
Doubler potentiellement l'audience
➔
Gagner en crédibilité

Inconvénient :
➔
Il faut programmer plusieurs fois la même chose
➔
Dans des langages différents (Java – Objective C)

Ce n'est pas une obligation, des alternatives existent
session sept 2014 Yann Caron (c) 2014 86
C++

Un tronc commun, le C++ finalement le
langage le plus multiplateforme (Cross-
compilation vs Interpretation VM)

Une stratégie : écrire le middleware en C++ et
les UI en natif sur les deux plateformes

Inconvénients : compliqué, difficile à mettre en
place (database ?, bibliothèque ?)
session sept 2014 Yann Caron (c) 2014 87
C++/Qt

Une alternative : Qt 5.2

La version 5 annonçait les prémices, la 5.2 officialise le portage
iOS et Android

Une UI non native, mais complètement portable (la force de Qt)

C++ plus rapide que Java

Pas de Garbage collector

On peut faire des jeux

Exemple : FlyingBus de Digia
session sept 2014 Yann Caron (c) 2014 88
Xaramin/Mono

Mono est une implémentation de la plateforme .net sur UNIX

Xaramin est une startup des créateurs de Mono pour viser les
plateformes mobiles

Solution payante (démo puis 299 $/année)

Mais un gain de temps

Et C# est vraiment un langage puissant
➔
Objet/Fonctionnel (Linq)
➔
Nombreux sucres syntaxiques : propriétés, évènements, lambdas, extension
méthods
➔
Un framework riche : Reflexion, Emit, LightWeight AOP (LinFu)
session sept 2014 Yann Caron (c) 2014 89
Xaramin

Un IDE multiplateforme (Win, MacOS), mais pas Linux
session sept 2014 Yann Caron (c) 2014 90
RobotVM

RobotVM compile le bytecode Java en Assembleur à
destination des processeurs ARM ou X86

Bridge avec les API Objective C comme CocoaTouch

Open source (GPLv2)

Support Eclipse (plugin) et Maven

Stratégie : développement en couche, middleware
commun en Java et deux applications UI natives

Le langage AL et JASI (le parser) fonctionnent
session sept 2014 Yann Caron (c) 2014 91
JavaFX

Expérimental

Utilisation de l'OpenJFX 8, projet non officiel :
https://bitbucket.org/javafxports/android/wiki/Home

Utilisation de RobotVM pour
viser iOS

Il existe même un plugin
NetBeans
session sept 2014 Yann Caron (c) 2014 92
IN01 – Séance 07
Autres
Jeux Vidéo Mobiles
session sept 2014 Yann Caron (c) 2014 93
Parts de marché

Le jeu vidéo mobile progresse de façon
spectaculaire sur le marché
Source : Flurry Analytics (un concurrent de Google Analytics)
session sept 2014 Yann Caron (c) 2014 94
Game engines

AndEngine :
➔
2D – OpenGL ES - Physic
➔
Android
➔
Java based – simple d'utilisation
➔
Gratuit et Open Source

JmonkeyEngine :
➔
3D – OpenGL ES
➔
Java based
➔
Open Source free BSD
session sept 2014 Yann Caron (c) 2014 95
Multiplateforme - Java

LibGDX :
➔
2D / 3D – OpenGL ES – Physics
➔
Multiplateforme (Android, iOS,
Sybian, Win, Linux, MacOS, html 5)
➔
RobotVM ©

cross compilation
➔
Java
➔
Open source
session sept 2014 Yann Caron (c) 2014 96
OpenFl

OpenFl :
➔
2d uniquement
➔
massivement multiplateforme
➔
Fonctionne sur le langage Haxe (multiparadigme)

Créé par un Français
➔
Sur une VM NekoVM dont l'intermediate language est
un langage de script (et pas du byteCode)
➔
Initialement inspiré par Flash
session sept 2014 Yann Caron (c) 2014 97
NoJava – Alternative 2D

Sencyl :
➔
2D, multiplateforme (iOS, Android, Flash, etc.)
➔
Basé sur OpenFl
➔
NoCode - Payant
session sept 2014 Yann Caron (c) 2014 98
No Java – Alternative 3D

Unity 3D :
➔
2D / 3D
➔
WYSIWYG Lua scripting
➔
Payant
session sept 2014 Yann Caron (c) 2014 99
NoJava – Alternative 3D

ShiVa 3D :
➔
3D multiplateforme
➔
WYSIWYD – Lua scripting
➔
Server MMO
➔
Gratuit
session sept 2014 Yann Caron (c) 2014 100
Fin
 Merci de votre attention
 Des questions ?

Contenu connexe

PDF
In01 - Programmation Android - Travaux pratiques
PDF
Programmation Android 07 - Techniques avancées
PDF
Programmation Android - Tp2 Travaux pratiques - Geomatique
PDF
In01 - Programmation Android - 04 - databases
PDF
In01 - Programmation Android - 05 - Google map
PDF
Programmation Android - 02 - Android
PDF
Programmation Android - 01 - Introduction
PDF
Programmation Android - 09 - Web services
In01 - Programmation Android - Travaux pratiques
Programmation Android 07 - Techniques avancées
Programmation Android - Tp2 Travaux pratiques - Geomatique
In01 - Programmation Android - 04 - databases
In01 - Programmation Android - 05 - Google map
Programmation Android - 02 - Android
Programmation Android - 01 - Introduction
Programmation Android - 09 - Web services

Tendances (10)

PDF
In01 - Programmation Android - 03 - HMI
PDF
Programmation Android - 06 - Publication
PDF
Programmation Android - 05 - Google map
PDF
In01 - Programmation Android - 06 - publication
PDF
Programmation Android - 00 - Présentation
PDF
Programmation Android - 04 - Databases
PDF
Programmation Android - 10 - Spatialite
PDF
In01 - Programmation Android - 02 - android
PDF
Programmation Android - 03 - IHM bases
PDF
Programmation Android - 08 - Android debug bridge
In01 - Programmation Android - 03 - HMI
Programmation Android - 06 - Publication
Programmation Android - 05 - Google map
In01 - Programmation Android - 06 - publication
Programmation Android - 00 - Présentation
Programmation Android - 04 - Databases
Programmation Android - 10 - Spatialite
In01 - Programmation Android - 02 - android
Programmation Android - 03 - IHM bases
Programmation Android - 08 - Android debug bridge
Publicité

En vedette (19)

PDF
In01 - Programmation Android - 01 - introduction
PDF
Programmation sous Android
PDF
Développement Android
PPTX
Android Studio, premier contact
PDF
Formation JavaScript full-stack (JS, jQuery, Node.js...)
PDF
Cours JavaScript
PDF
Alphorm.com Formation Android 5
PPTX
Android cours
PPT
PPT
Introductions Aux Servlets
PPT
Les Servlets et JSP
PDF
Ecoscan guide fr
PPTX
Pilote5
PPTX
Coordination of Activities in Dynamic Situations – The Case Of Crisis Management
PPT
Les outils technologiques au service de l'accueil sur le territoire : le proj...
PDF
SQLite 3
KEY
Les applications mobiles
PPTX
Keynote IEEE Wetice conference 2016 - From group collaboration to large scale...
PPTX
Présentation de Node.js
In01 - Programmation Android - 01 - introduction
Programmation sous Android
Développement Android
Android Studio, premier contact
Formation JavaScript full-stack (JS, jQuery, Node.js...)
Cours JavaScript
Alphorm.com Formation Android 5
Android cours
Introductions Aux Servlets
Les Servlets et JSP
Ecoscan guide fr
Pilote5
Coordination of Activities in Dynamic Situations – The Case Of Crisis Management
Les outils technologiques au service de l'accueil sur le territoire : le proj...
SQLite 3
Les applications mobiles
Keynote IEEE Wetice conference 2016 - From group collaboration to large scale...
Présentation de Node.js
Publicité

Similaire à In01 - Programmation Android - 07 - techniques avancées (20)

PDF
Windows Phone Workshop sensors and battery
PPTX
Les capteurs sous android
PPTX
Android
PDF
Android201710 avrilcours3
PDF
Présentation paug icecreamsandwich
PDF
GDG Rennes - Bootcamp Initiation Android - Théorie
PPTX
Android Lab Test : Le capteur gyroscope (français)
PDF
Android introvf
PDF
Android Optimisations Greendroid
PDF
Android-Tp2: liste et adaptateurs
PPTX
Introduction au développement Android
PDF
introAndroid_2023_V6.5.2pp1-162.pdf
PDF
Android workshop - Bootcamp du Mauriapp Challenge 2016
PDF
Bootcamp d'Initiation à Android - 2013/11/30
PDF
TP_1.pdf
PPTX
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1
PDF
Meetup#1 talk#1
PDF
Tech Conf n°1 - Développement natif d'applications mobiles
PPTX
PAUG 03/05/2016 : Android Studio Rappels
Windows Phone Workshop sensors and battery
Les capteurs sous android
Android
Android201710 avrilcours3
Présentation paug icecreamsandwich
GDG Rennes - Bootcamp Initiation Android - Théorie
Android Lab Test : Le capteur gyroscope (français)
Android introvf
Android Optimisations Greendroid
Android-Tp2: liste et adaptateurs
Introduction au développement Android
introAndroid_2023_V6.5.2pp1-162.pdf
Android workshop - Bootcamp du Mauriapp Challenge 2016
Bootcamp d'Initiation à Android - 2013/11/30
TP_1.pdf
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1
Meetup#1 talk#1
Tech Conf n°1 - Développement natif d'applications mobiles
PAUG 03/05/2016 : Android Studio Rappels

Plus de Yann Caron (13)

PDF
Théorie des langages - TP - WellKnownText
PDF
Théorie des langages - 04 Théorie des langages
PDF
Théorie des langages - 03 - Principes et paradigmes
PDF
Théorie des langages - 02 - Code gen
PDF
Théorie des langages - 01.1 - Parcours d'arbres
PDF
Théorie des langages - 01 - Compilation
PDF
Théorie des langages - 00 - Introduction
PDF
Algea - 04 - conclusion
PDF
Algea - 03 - ennemis
PDF
Algea - 02 - gemmes
PDF
Algea - 01 - hero
PDF
ALGEA - 00 - introduction
PDF
Cours CNAM In01 - Programmation Android - Septembre 2014
Théorie des langages - TP - WellKnownText
Théorie des langages - 04 Théorie des langages
Théorie des langages - 03 - Principes et paradigmes
Théorie des langages - 02 - Code gen
Théorie des langages - 01.1 - Parcours d'arbres
Théorie des langages - 01 - Compilation
Théorie des langages - 00 - Introduction
Algea - 04 - conclusion
Algea - 03 - ennemis
Algea - 02 - gemmes
Algea - 01 - hero
ALGEA - 00 - introduction
Cours CNAM In01 - Programmation Android - Septembre 2014

In01 - Programmation Android - 07 - techniques avancées

  • 1. session sept 2014 Yann Caron (c) 2014 1 IN01 Programmation Android 07 – Techniques avancées Yann Caron
  • 2. session sept 2014 Yann Caron (c) 2014 2 Sommaire - Séance 07  Programmation avancée ➔ Capteurs ➔ Optimisations ➔ Tests unitaires ➔ Concurrence  IHM avancées ➔ Vues personnalisées ➔ Fragments  Autres ➔ Stratégies et alternatives ➔ Jeux vidéo mobiles
  • 3. session sept 2014 Yann Caron (c) 2014 3 IN01 – Séance 07 Programmation avancée Capteurs
  • 4. session sept 2014 Yann Caron (c) 2014 4 Généralités  La miniaturisation et l'industrialisation rendent aujourd'hui accessibles des capteurs précis au grand public  La majorité des appareils Android embarquent au moins un accéléromètre, un gyroscope et un magnétomètre  Les trois tiennent sur ce circuit :
  • 5. session sept 2014 Yann Caron (c) 2014 5 Différents capteurs Android TYPE_ACCELE ROMETER 3 m/s2 Mesure de l'accélération (gravité incluse) [0] axe x [1] axe y [2] axe z TYPE_GYROS COPE 3 Rad / s Mesure la rotation en termes de vitesse autour de chaque axe [0] vitesse x [1] vitesse y [2] vitesse z TYPE_LIGHT 1 Lux Mesure de la luminosité [0]valeur TYPE_MAGNE TIC_FIELD 3 µTesla Mesure du champ magnétique [0] axe x [1] axe y [2] axe z TYPE_ORIENT ATION 3 degrés Mesure l'angle entre le nord magnétique [0] Azimut y / nord [1] Rotation x (- 180,180) [2] Rotation y (-90,90) TYPE_PRESSU RE 1 KPas Mesure la pression [0]valeur TYPE_PROXIM ITY 1 mètre Mesure la distance entre l'appareil et un objet cible [0]valeur TYPE_TEMPER ATURE 1 Celsius Mesure la température [0]valeur
  • 6. session sept 2014 Yann Caron (c) 2014 6 Présence du capteur  On peut interdire (ou pas) l'utilisation de l'application aux appareils qui ne possèdent pas un certain capteur  Utile si votre application ne peut pas fonctionner sans de façon correcte  Dans le manifest (toujours !!) : <uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true" />
  • 7. session sept 2014 Yann Caron (c) 2014 7 Sensor Manager  Pour accéder aux senseurs, on appelle une méthode de l'Activity qui renvoie un objet de type SensorManager  On peut récupérer la liste des capteurs disponibles sur l'appareil SensorManager sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE); ArrayList<Sensor> liste = (ArrayList<Sensor>) sensorManager.getSensorList(Sensor.TYPE_MAGNETIC_FIELD);
  • 8. session sept 2014 Yann Caron (c) 2014 8 Obtenir une instance de capteur  On peut maintenant obtenir une instance du capteur souhaité  Attention !! Si le capteur n'est pas disponible, l'objet renvoie la valeur null. Si le capteur n'est pas requis, il faut tester et gérer s'il est absent. Sensor accelerometre = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
  • 9. session sept 2014 Yann Caron (c) 2014 9 Évènement  Les capteurs fonctionnent aussi sur un modèle évènementiel final SensorEventListener mSensorEventListener = new SensorEventListener() { public void onAccuracyChanged(Sensor sensor, int accuracy) { // Que faire en cas de changement de précision ? } public void onSensorChanged(SensorEvent sensorEvent) { // Que faire en cas d'évènements sur le capteur ? } }; Si la précision a changé Si les valeurs ont changé
  • 10. session sept 2014 Yann Caron (c) 2014 10 Évènement  Attention, il est préférable d'enregistrer l'évènement lorsque l'application est active et de le désenregistrer lorsque celle-ci est inactive  Sinon, il continue de s'exécuter @Override protected void onResume() { super.onResume(); mSensorManager.registerListener(mSensorEventListener, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); } @Override protected void onPause() { super.onPause(); mSensorManager.unregisterListener(mSensorEventListener, mAccelerometer); }
  • 11. session sept 2014 Yann Caron (c) 2014 11 Évènement – Valeurs  L'évènement du capteur renvoie un tableau de valeurs float  Leur nombre et leur signification varient selon les capteurs (voir tableau précédent) public void onSensorChanged(SensorEvent sensorEvent) { float[] values = sensorEvent.values; Log.d("Sensors", "Acceleration sur l'axe x : " + values[0]); Log.d("Sensors", "Acceleration sur l'axe y : " + values[1]); Log.d("Sensors", "Acceleration sur l'axe z : " + values[2]); }
  • 12. session sept 2014 Yann Caron (c) 2014 12 Rotation  Doit être calculée avec les valeurs de l'accéléromètre et du magnétomètre combinées à l'aide de formules complexes  Deux méthodes existent pour faciliter ce calcul : getRotationMatrix() et getOrientation() float[] values = new float[3]; float[] R = new float[9]; SensorManager.getRotationMatrix(R, null, accelerometreValues, magnetometreValues); SensorManager.getOrientation(R, values); Log.d("Sensors", "Rotation sur l'axe z : " + values[0]); Log.d("Sensors", "Rotation sur l'axe x : " + values[1]); Log.d("Sensors", "Rotation sur l'axe y : " + values[2]);
  • 13. session sept 2014 Yann Caron (c) 2014 13 Quelques applications
  • 14. session sept 2014 Yann Caron (c) 2014 14 IN01 – Séance 07 Programmation avancée Optimisation
  • 15. session sept 2014 Yann Caron (c) 2014 15 Optimisation sous Android  Pourquoi ?? ➔ Pour de meilleures performances !!  Oui, mais pour qui ?? ➔ Les applications de bas niveau (un compilateur de langage comme Algoid par exemple ;-)) ➔ Des applications gourmandes en ressources (les jeux vidéo, les applications graphiques)
  • 16. session sept 2014 Yann Caron (c) 2014 16 Règles – Les objets  Éviter de créer des objets non nécessaires  En règle générale, éviter de créer trop d'objets ! ➔ Parce que la création d'objets c'est gourmand ➔ Et la destruction encore pire : la dalvikVM bloque tout processus lors du GC (GC dit Stop the World) ➔ Préférer les StringBuffer aux concaténations de strings à outrance ➔ Un tableau d'int est meilleur qu'un tableau d'integer (utilisation des types primitifs)
  • 17. session sept 2014 Yann Caron (c) 2014 17 Règles – Les listes  Un tableau est meilleur qu'une ArrayList, même règle que précédemment sur les types primitifs  Une ArrayList est moins coûteuse à lire qu'une LinkedList (création d'objets entry qui seront à gérer par le GC)
  • 18. session sept 2014 Yann Caron (c) 2014 18 Règles – Les boucles  Idéal :  Catastrophique : int size = myArray.length); for (int i = 0; i < size; i ++) { } La taille est évaluée à chaque itération Map<Integer, String> myMap = new HashMap(); for (Entry<Integer, String> item : myMap.entrySet()) { } Un objet Entry<Key, Value> créé à chaque itération
  • 19. session sept 2014 Yann Caron (c) 2014 19 Règles – Méthodes et variables  Préférer les méthodes statiques aux méthodes de classe, si aucun attribut de la classe n'est nécessaire  Utiliser static final pour les constantes  Éviter les inner class, surtout si elles ne sont pas statiques  Éviter les getter et setter (antipattern)  Les float 2x plus lents que les int  Les double sont 2x plus gourmands en mémoire que les float
  • 20. session sept 2014 Yann Caron (c) 2014 20 Règles - Conclusion  Attention toutefois à ne pas abuser des règles d'optimisation  Évaluer si l'application nécessite une optimisation  Toujours mettre en relation le gain de performances (CPU/Mem) et la lisibilité du code  Car attention ! Ces règles dégradent la qualité du code et donc la lisibilité et la réutilisabilité
  • 21. session sept 2014 Yann Caron (c) 2014 21 Optimisation - Outils  Toujours mesurer les gains par des micro-benchmarks :  Et le JIT (Just In Time Compiler) ?  Profilers netbeans ou Eclipse sont nos amis  Résultat : Algoid Language aussi rapide que Python est plus rapide que JavaScript sur Android :-) Pas mal pour un langage seulement interprété force brute long time = System.currentTimeMillis(); for (int i=0; i<1000000; i++) { // le code à tester } long timeSpent = System.currentTimeMillis() - time; System.out.println("Time spent " + timeSpent);
  • 22. session sept 2014 Yann Caron (c) 2014 22 IN01 – Séance 07 Programmation avancée Tests unitaires
  • 23. session sept 2014 Yann Caron (c) 2014 23 Vue d'ensemble  Créer des tests unitaires pour tester des apps Android, c'est possible  Ça fonctionne avec JUnit  On peut tester l'interface utilisateur (manipulation)
  • 24. session sept 2014 Yann Caron (c) 2014 24 Création du projet de test  Depuis Eclipse
  • 25. session sept 2014 Yann Caron (c) 2014 25 Création du projet de test  On choisit le projet à tester
  • 26. session sept 2014 Yann Caron (c) 2014 26 Test Fixture  Pour créer un test case, il suffit de créer une nouvelle classe de test  Celle-ci devra hériter de la classe ActivityInstrumentationTestCase2  Et fournir la classe à tester dans son constructeur public class ActivityTest extends ActivityInstrumentationTestCase2<MainActivity>{ public ActivityTest() { super(MainActivity.class); } } La Classe à tester
  • 27. session sept 2014 Yann Caron (c) 2014 27 SetUp  Lors du setUp, on récupère les instances de l'activity et des composants à tester private MainActivity activity = null; private TextView myTextView = null; private Button myButton = null; @Override protected void setUp() throws Exception { super.setUp(); activity = getActivity(); myTextView = (TextView) activity.findViewById( fr.cnam.helloworld.R.id.myTextView); myButton = (Button)activity.findViewById( fr.cnam.helloworld.R.id.myButton); } R (ressources) du projet à tester
  • 28. session sept 2014 Yann Caron (c) 2014 28 Préconditions  Une bonne pratique consiste à tester que le setUp s'est bien déroulé @SmallTest public void testPreconditions() { assertNotNull("activity is null", activity); assertNotNull("myTextView is null", myTextView); assertNotNull("myButton is null", myButton); }
  • 29. session sept 2014 Yann Caron (c) 2014 29 Layout test  Tester le layout des composants @MediumTest public void testMyTextView_layout() { final View decorView = activity.getWindow().getDecorView(); ViewAsserts.assertOnScreen(decorView, myTextView); final ViewGroup.LayoutParams layoutParams = myTextView.getLayoutParams(); assertNotNull(layoutParams); assertEquals(layoutParams.width, WindowManager.LayoutParams.WRAP_CONTENT); assertEquals(layoutParams.height, WindowManager.LayoutParams.WRAP_CONTENT); } Test que le composant est présent
  • 30. session sept 2014 Yann Caron (c) 2014 30 @MediumTest public void testMyButton_click() { String initialText = activity.getString( fr.cnam.helloworld.R.string.hello_world); String expectedText = activity.getString( fr.cnam.helloworld.R.string.after_click); assertEquals(initialText, myTextView.getText()); TouchUtils.clickView(this, myButton); assertEquals(expectedText, myTextView.getText()); } Tester les comportements souhaités  Utilisation de TouchUtils pour simuler les actions utilisateur Clic sur le bouton
  • 31. session sept 2014 Yann Caron (c) 2014 31 Test Annotations  @SmallTest : ➔ Un test court, moins de 100 ms  @MediumTest : ➔ Un test de durée moyenne, supérieure à 100 ms  @LargeTest : ➔ Idem que le mediumTest, avec un accès plus important aux ressources
  • 32. session sept 2014 Yann Caron (c) 2014 32 Résultats  Et voilà le travail !!  Les sources complètes sont dans le projet du cours  Bons tests !!
  • 33. session sept 2014 Yann Caron (c) 2014 33 IN01 – Séance 07 Programmation avancée Concurrence
  • 34. session sept 2014 Yann Caron (c) 2014 34 Généralités  Pour gérer des traitements et pour ne pas bloquer l'interface utilisateur, on utilise des Threads  Problème !! Il nous est interdit de modifier l'IHM depuis un autre Thread que le Thread principal  Deux outils existent sur Android : Handler et AsyncTask  cf. SwingWorker de Swing
  • 35. session sept 2014 Yann Caron (c) 2014 35 Handler - Pattern  Son but : synchroniser de petites tâches et les ordonner (comme un ordonnanceur)  Un handler particulier attaché à l'IHM  C'est une queue de tâches  Le consommateur se met en attente sur la queue  Lorsqu'une tâche est ajoutée par un des multiples producteurs (threads), la queue est notifiée, débloquant ainsi le consommateur  Lorsque le consommateur a tout consommé, il se remet en attente  Ça ressemble au patron Reader – Writer lock, mais, inversé (multiple writer et mono reader)  Utilisation massive dans Algoid (le script emploie son propre thread)
  • 36. session sept 2014 Yann Caron (c) 2014 36 Handler - Utilisation  Il faut créer un handler (ou en récupérer un d'une vue)  Puis lui envoyer des tâches Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } });
  • 37. session sept 2014 Yann Caron (c) 2014 37 Handler - Les méthodes  Plusieurs méthodes pour poster une tâche sont disponibles : ➔ post() : place la tâche à la fin de la queue (sera exécutée après toutes les autres) ➔ postAtFrontOfQueue() : place la tâche au début, juste après celle en cours d'exécution ➔ postAtTime() : place la tâche avec un marqueur temps ➔ postDelayed() : place la tâche avec un marqueur de délai
  • 38. session sept 2014 Yann Caron (c) 2014 38 AsyncTask  Utilisé pour des tâches généralement plus longues  Et/ou, pour gérer l'affichage de la progression dans l'IHM  On utilise la classe AsyncTask  <TypeDesParamètres,  TypeDeProgression, TypeDuRésultat>
  • 39. session sept 2014 Yann Caron (c) 2014 39 AsyncTast - Création class MyAsyncTask extends AsyncTask<String, Integer, String> { @Override protected String doInBackground(String... params) { return null; } @Override protected void onCancelled(String result) { } @Override protected void onPostExecute(String result) { } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); } } Si la tâche est annulée Tâche principale Une fois finie Gérer la progression
  • 40. session sept 2014 Yann Caron (c) 2014 40 AsyncTask - Utilisation  Il suffit maintenant de l'instancier et de la lancer  Les données seront transférées dans les paramètres de la méthode doInBackground(String... params) MyAsyncTask task = new MyAsyncTask(); task.execute(new String[] { "my String" });
  • 41. session sept 2014 Yann Caron (c) 2014 41 IN01 – Séance 07 IHM avancées Vues personnalisées
  • 42. session sept 2014 Yann Caron (c) 2014 42 Vue d'ensemble  Les Activities sont utilisées pour agréger des vues ensemble (traitement d'un ensemble de données)  Une vue permet de traiter une donnée en particulier  Il existe quatre façons de créer des vues personnalisées : ➔ Une vue composée (héritage d'une sous-classe de ViewGroup) ➔ Un layout (héritage de ViewGroup) ➔ Spécialisation d'une vue existante (héritage d'une sous-classe de View) ➔ Création d'une vue de bout en bout (hérite de View)  Possibilité de combiner les approches
  • 43. session sept 2014 Yann Caron (c) 2014 43 Vue composée  On doit créer une classe qui hérite d'une classe elle-même héritant d'un viewGroup  Par exemple LinearLayout  Ensuite, dans le constructeur ou dans une méthode spécifique, on ajoute dynamiquement des vues enfants !!
  • 44. session sept 2014 Yann Caron (c) 2014 44 Vue composée  Deux façons d'ajouter des composants : ➔ Par programmation grâce à la méthode addView (héritée de view) ➔ Par XML avec la méthode LayoutInflater public class MyView extends LinearLayout { public MyView(Context context, AttributeSet attrs) { super(context, attrs); EditText txt1 = new EditText(context); EditText txt2 = new EditText(context); super.addView(txt1); super.addView(txt2); } }
  • 45. session sept 2014 Yann Caron (c) 2014 45 Vue composée - Utilisation  Utile pour afficher des listes de données, des tableaux  Dans Algoid j'ai utilisé cette technique pour : ➔ Le File Manager  Construction dynamique de la vue en fonction des fichiers ➔ Invite de commande  Entrées sorties utilisateur pilotées par programme ➔ Scope View  Construction d'une vue hiérarchique en fonction de l'état de la mémoire
  • 46. session sept 2014 Yann Caron (c) 2014 46 Création d'un layout  Principe : hériter de la classe ViewGroup  Surcharger la méthode onLayout et placer les vues enfants (getChildCount() et getChildAt()) public class MyLayout extends ViewGroup{ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { for (int i = 0; i< getChildCount(); i++) { View child = this.getChildAt(i); child.setX(10); child.setY(10 * i); } } }
  • 47. session sept 2014 Yann Caron (c) 2014 47 Spécialisation  Principe : hériter d'une vue existante (elle-même spécialisation de la classe View)  Ajouter des comportements en surchargeant des méthodes (il faut bien lire la documentation)  Ajouter des comportements sur des évènements (onTouch, onLongClick,onKey)  Ajouter des dessins (surcharge de la méthode onDraw)
  • 48. session sept 2014 Yann Caron (c) 2014 48 Spécialisation – Exemple  L'IDE d'Algoid par exemple : AutoCompletion, coloration syntaxique et breakpoints public class SourceEditorTextView extends MultiAutoCompleteTextView { public SourceEditorTextView(Context context, AttributeSet attrs) { super(context, attrs); setOnLongClickListener(new OnLongClickListener() { // ajouter les breakpoints } } @Override protected void onDraw(Canvas canvas) { // dessiner ici les breakpoints super.onDraw(canvas); } } En réalité, 3 constructeurs Ajoute un breakpoint Dessine les breakpoints
  • 49. session sept 2014 Yann Caron (c) 2014 49 Création de bout en bout  Principe : hériter de la classe View  Comme une vue spécialisée, mais sans comportement préalable ➔ Gérer des évènements et implémenter les méthodes nécessaires comme onDraw  Peut être long et fastidieux, il vaut mieux bien évaluer si la vue n'existe pas au préalable  Exemple : Algo la petite tortue
  • 50. session sept 2014 Yann Caron (c) 2014 50 Utilisation de la vue  Une fois la vue créée, il est possible de l'ajouter à un conteneur : ➔ Activity, ViewGroup, Fragment  Toujours de deux façons : ➔ En Java ➔ En XML addView(new MyView(context, attrs)); <fr.cnam.in01.techniques.MyView android:id="@+id/myView" myView:text1="myText1" myView:text2="myText2"/>
  • 51. session sept 2014 Yann Caron (c) 2014 51 Paramètres personnalisés  Plusieurs étapes pour créer un attribut personnalisé  But : pouvoir paramétrer la vue depuis des valeurs passées dans l'XML  Un “Vrai” composant graphique !!
  • 52. session sept 2014 Yann Caron (c) 2014 52 Paramètres personnalisés  Pour chaque attribut (ici text1 et text2), il faut créer une paire getter/setter (setText1 etc.)  Il faut déclarer ces attributs dans une ressource sous res/values/attrs.xml <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MyView"> <attr name="text1" format="string" /> <attr name="text2" format="string" /> </declare-styleable> </resources>
  • 53. session sept 2014 Yann Caron (c) 2014 53 Paramètres personnalisés  Il faut ensuite déclarer le nouveau NameSpace dans le fichier XML de l'activity (là où est utilisé MyView)  Puis utiliser les paramètres dans la déclaration du composant xmlns:myview="http://schemas.android.com/apk/res-auto" <fr.cnam.in01.techniques.MyView android:id="@+id/myView" myview:text1="myText one" myview:text2="myText two"/>
  • 54. session sept 2014 Yann Caron (c) 2014 54 Paramètres personnalisés  Et enfin, récupérer les valeurs dans le constructeur de la vue public MyView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray typedAttrs = getContext() .obtainStyledAttributes(attrs, R.styleable.MyView); String text1 = typedAttrs.getString(R.styleable.MyView_text1); txt1.setText(text1); String text2 = typedAttrs.getString(R.styleable.MyView_text2); txt2.setText(text2); }
  • 55. session sept 2014 Yann Caron (c) 2014 55 Conclusion  De quoi créer des bibliothèques de composants entièrement personnalisées  Idéal pour la réutilisabilité du code  Ou la distribution de celui-ci  Pourtant, encore assez peu de bibliothèques graphiques ne sont disponibles sur Android !!
  • 56. session sept 2014 Yann Caron (c) 2014 56 IN01 – Séance 07 IHM avancées Fragments
  • 57. session sept 2014 Yann Caron (c) 2014 57 Vue d'ensemble  Un fragment est un composant graphique qui se situe entre la vue et l'activity  Il est lié à une activity  Il peut être graphique ou logique  Il peut être chargé/déchargé dynamiquement (par programmation)  Ou être utilisé de façon statique (en XML)  Il est disponible depuis la version 11 de l'API (HoneyComb), mais grâce à l'app compat générée avec un projet Android, il peut être utilisé sur des API plus anciennes  Il sert à adapter les interfaces aux différentes résolutions des appareils
  • 58. session sept 2014 Yann Caron (c) 2014 58 Vue d'ensemble  Les activities peuvent être composées d'un ou plusieurs fragments en fonction de la place à disposition
  • 59. session sept 2014 Yann Caron (c) 2014 59 Cycle de vie  Il a son propre cycle de vie  Cela permet d'isoler son comportement et ainsi de rendre plus “léger” le code de l'activity  onAttach : sert à récupérer l'instance de l'activity  onCreate : sert à instancier les objets non graphiques  onCreateView : idem, mais graphiques  onStart : lancer les traitements  onResume : s'abonner aux évènements, récupérer le contexte  onPause : s'y désabonner et sauver le contexte  onStop, onDestroyView, onDestroy, onDetach : on désalloue les ressources créées ci-dessus
  • 60. session sept 2014 Yann Caron (c) 2014 60 Création d'un fragment  Un fichier XML, comme pour une activity <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <!-- content --> </LinearLayout>
  • 61. session sept 2014 Yann Caron (c) 2014 61 Création d'un fragment  Et la classe associée (qui hérite de Fragment)  Laquelle implémente l'évènement onCreateView public class MenuFragment extends Fragment @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) { View view = inflater.inflate(R.layout.menu_fragment, container, false); return view; }
  • 62. session sept 2014 Yann Caron (c) 2014 62 layout/main_activity <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="fr.cnam.in01.in01_fragments.MainActivity" tools:ignore="MergeRootFrame" > <fragment android:id="@+id/menu" android:name="fr.cnam.in01.in01_fragments.MenuFragment" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" /> </FrameLayout> Un seul fragment
  • 63. session sept 2014 Yann Caron (c) 2014 63 layout-land/main_activity <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:orientation="horizontal"> <fragment android:name="fr.cnam.in01.in01_fragments.MenuFragment" android:layout_height="match_parent" android:layout_width="0dp" android:layout_weight="1" /> <fragment android:name="fr.cnam.in01.in01_fragments.MainFragment" android:layout_height="match_parent" android:layout_width="0dp" android:layout_weight="2" /> </LinearLayout> Plusieurs fragments
  • 64. session sept 2014 Yann Caron (c) 2014 64 Instance du fragment  Dans la méthode onLoad() de l'activity, on a accès à l'instance du/des fragments  Attention, ils peuvent ne pas exister dans le XML, leur référence est null dans ce cas !!  On utilise la méthode Activity.getFragmentManager() MenuFragment fragment = (MenuFragment) getFragmentManager() .findFragmentById(R.id.menu);
  • 65. session sept 2014 Yann Caron (c) 2014 65 Du fragment vers l'activity  Pour que les fragments soient réutilisables, il ne faut pas qu'ils communiquent directement avec l'activity  On utilise une inversion de dépendance  Par exemple un template method (design pattern, peu utilisé dans les IHM)  Ou un observer/observable
  • 66. session sept 2014 Yann Caron (c) 2014 66 Évènements  On définit une interface et un mécanisme d'évènement public class MenuFragment extends Fragment { private MenuChangeEvent menuChanged; public interface MenuChangeEvent { void menuChanger(int id); } public void setOnMenuChange(MenuChangeEvent menuChanged) { this.menuChanged = menuChanged; } private void fireMenuChanged(int id) { if (this.menuChanged != null) { this.menuChanged.menuChanger(id); } } Invertion de dépendance Abonnement
  • 67. session sept 2014 Yann Caron (c) 2014 67 Évènements  Dans l'activity, lorsque le fragment est chargé, on s'abonne à l'évènement menuFragment.setOnMenuChange(new MenuChangeEvent() { @Override public void menuChanger(int id) { switch (id) { case R.id.button1: navigate(MenuFragment.class); break; case R.id.button2: navigate(MainFragment.class); break; } } });
  • 68. session sept 2014 Yann Caron (c) 2014 68 Placeholder  Les fragments peuvent être placés de façon statique dans le XML, comme on l'a vu  Ils peuvent également être chargés dynamiquement (par programmation) dans des placeholders  En général, on utilise des FrameLayout
  • 69. session sept 2014 Yann Caron (c) 2014 69 Placeholder <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <FrameLayout android:id="@+id/placeholder1" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" /> <FrameLayout android:id="@+id/placeholder2" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="2" /> </LinearLayout>
  • 70. session sept 2014 Yann Caron (c) 2014 70 Placeholder  On peut ensuite, charger les fragments à l'aide d'un objet de type FragmentTransaction  La méthode addToBackStack permet de gérer le bouton back (conserve un historique des fragments chargés, comme pour les activities) FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.replace(placeholder, fragment); ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); ft.addToBackStack(null); ft.commit();
  • 71. session sept 2014 Yann Caron (c) 2014 71 Navigation  Ensuite, selon le nombre de placeholder à disposition, on choisit quel type de navigation l'on souhaite : ➔ Une seule, on peut lancer une nouvelle activity ou remplacer le placeholder 1 ➔ Deux, on peut choisir le placeholder à charger et remplacer le précédent  Le mieux étant de toujours passer le nom de la classe du fragment de façon à l'instancier par introspection Class<? extends Fragment> frClass = MenuFragment.class; Fragment fragment = frClass.newInstance();
  • 72. session sept 2014 Yann Caron (c) 2014 72 Persistance des états du fragment  On l'a vu, les Fragments sont des objets autonomes avec leur cycle de vie propre  L'idée initiale est de décharger l'activity des tâches propres aux sous-éléments graphiques qui se chargent et se déchargent de façon dynamique  De cette façon, il est possible de gérer la sauvegarde des états dans un Bundle  Comme pour les activity, on utilise les évènements du cycle de vie du fragment : onCreateView() et onSaveInstanceState()
  • 73. session sept 2014 Yann Caron (c) 2014 73 Menus  Les fragments apportent leur propre menu lorsqu'ils sont chargés public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); } public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.fragment_menu, menu); super.onCreateOptionsMenu(menu, inflater); } public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.fragment_menu_item1: // Action 1 return true; default: // Quelqu'un d'autre peut gérer ce menu return super.onOptionsItemSelected(item); } }
  • 74. session sept 2014 Yann Caron (c) 2014 74 Navigation drawer  Un menu qui glisse quand on en a besoin  Source : http://developer.android. com/training/implement ing-navigation/nav- drawer.html
  • 75. session sept 2014 Yann Caron (c) 2014 75 Navigation drawer  Création de l'activity <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:id="@+id/content_frame" android:layout_width="match_parent" android:layout_height="match_parent" /> <ListView android:id="@+id/left_drawer" android:layout_width="240dp" android:layout_height="match_parent" android:layout_gravity="start" android:choiceMode="singleChoice" android:divider="@android:color/transparent"/> </android.support.v4.widget.DrawerLayout> Contenu Menu sous forme de liste
  • 76. session sept 2014 Yann Caron (c) 2014 76 Navigation drawer  Chargement du menu dans l'activity @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView menu = (ListView) findViewById(R.id.menu); String[] menuItems = getResources().getStringArray(R.array.menu_items_array); // Set the adapter for the list view menu.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, menuItems)); // Set the list's click listener menu.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // TODO Auto-generated method stub } }); } Items dans des tableaux res/values Gestion des événements Icône + texte
  • 77. session sept 2014 Yann Caron (c) 2014 77 Navigation drawer  Idéal avec les fragments  Google fournit un ensemble d'icônes  http://developer.android.com/downloads/desi gn/Android_Design_Icons_20130926.zip
  • 78. session sept 2014 Yann Caron (c) 2014 78 Navigation drawer
  • 79. session sept 2014 Yann Caron (c) 2014 79 Conclusion  Les fragments offrent une réelle souplesse dans l'organisation des IHM en fonction des résolutions  Une bonne pratique consiste à toujours concevoir ses IHM selon des fragments, même pour des apps ne nécessitant que peu d'écran  Une navigation plus riche pourra être conçue par la suite  Les composants de l'application bénéficieront également d'une plus grande réutilisabilité
  • 80. session sept 2014 Yann Caron (c) 2014 80 IN01 – Séance 07 Autres Stratégies et alternatives
  • 81. session sept 2014 Yann Caron (c) 2014 81 Stratégie – Choix de l'application  Red Ocean Strategy : ➔ Compléter un marché existant ➔ Exploiter une demande existante ➔ Battre la concurrence  Exemples : Pet rescue, Points and clicks  Avantage : Le marché existe déjà  Inconvénient : Pas d'innovation, pas passionnant
  • 82. session sept 2014 Yann Caron (c) 2014 82 Stratégie – Choix de l'application  Blue Ocean Strategy : ➔ Créer un marché inexploité ➔ Créer ou capter de nouveaux besoins ➔ Pas de concurrence  Exemple : AIDE  Avantages : Avoir une longueur d'avance, être innovant, développement motivant  Difficultés : Identifier le besoin, faire connaitre son application
  • 83. session sept 2014 Yann Caron (c) 2014 83 Dégager du revenu  Android une plateforme où il est difficile de dégager du revenu
  • 84. session sept 2014 Yann Caron (c) 2014 84 Enjeux du multiplateforme  De plus, il existe beaucoup d'applications sur le Play Store (phénomène de flooding, noyade)  Les utilisateurs n'ont pas l'habitude d'acheter sur cette plateforme  Il vaut mieux viser la publicité  Une meilleure stratégie consiste à viser plusieurs plateformes
  • 85. session sept 2014 Yann Caron (c) 2014 85 Enjeux du multiplateforme  Double avantage : ➔ Doubler potentiellement l'audience ➔ Gagner en crédibilité  Inconvénient : ➔ Il faut programmer plusieurs fois la même chose ➔ Dans des langages différents (Java – Objective C)  Ce n'est pas une obligation, des alternatives existent
  • 86. session sept 2014 Yann Caron (c) 2014 86 C++  Un tronc commun, le C++ finalement le langage le plus multiplateforme (Cross- compilation vs Interpretation VM)  Une stratégie : écrire le middleware en C++ et les UI en natif sur les deux plateformes  Inconvénients : compliqué, difficile à mettre en place (database ?, bibliothèque ?)
  • 87. session sept 2014 Yann Caron (c) 2014 87 C++/Qt  Une alternative : Qt 5.2  La version 5 annonçait les prémices, la 5.2 officialise le portage iOS et Android  Une UI non native, mais complètement portable (la force de Qt)  C++ plus rapide que Java  Pas de Garbage collector  On peut faire des jeux  Exemple : FlyingBus de Digia
  • 88. session sept 2014 Yann Caron (c) 2014 88 Xaramin/Mono  Mono est une implémentation de la plateforme .net sur UNIX  Xaramin est une startup des créateurs de Mono pour viser les plateformes mobiles  Solution payante (démo puis 299 $/année)  Mais un gain de temps  Et C# est vraiment un langage puissant ➔ Objet/Fonctionnel (Linq) ➔ Nombreux sucres syntaxiques : propriétés, évènements, lambdas, extension méthods ➔ Un framework riche : Reflexion, Emit, LightWeight AOP (LinFu)
  • 89. session sept 2014 Yann Caron (c) 2014 89 Xaramin  Un IDE multiplateforme (Win, MacOS), mais pas Linux
  • 90. session sept 2014 Yann Caron (c) 2014 90 RobotVM  RobotVM compile le bytecode Java en Assembleur à destination des processeurs ARM ou X86  Bridge avec les API Objective C comme CocoaTouch  Open source (GPLv2)  Support Eclipse (plugin) et Maven  Stratégie : développement en couche, middleware commun en Java et deux applications UI natives  Le langage AL et JASI (le parser) fonctionnent
  • 91. session sept 2014 Yann Caron (c) 2014 91 JavaFX  Expérimental  Utilisation de l'OpenJFX 8, projet non officiel : https://bitbucket.org/javafxports/android/wiki/Home  Utilisation de RobotVM pour viser iOS  Il existe même un plugin NetBeans
  • 92. session sept 2014 Yann Caron (c) 2014 92 IN01 – Séance 07 Autres Jeux Vidéo Mobiles
  • 93. session sept 2014 Yann Caron (c) 2014 93 Parts de marché  Le jeu vidéo mobile progresse de façon spectaculaire sur le marché Source : Flurry Analytics (un concurrent de Google Analytics)
  • 94. session sept 2014 Yann Caron (c) 2014 94 Game engines  AndEngine : ➔ 2D – OpenGL ES - Physic ➔ Android ➔ Java based – simple d'utilisation ➔ Gratuit et Open Source  JmonkeyEngine : ➔ 3D – OpenGL ES ➔ Java based ➔ Open Source free BSD
  • 95. session sept 2014 Yann Caron (c) 2014 95 Multiplateforme - Java  LibGDX : ➔ 2D / 3D – OpenGL ES – Physics ➔ Multiplateforme (Android, iOS, Sybian, Win, Linux, MacOS, html 5) ➔ RobotVM ©  cross compilation ➔ Java ➔ Open source
  • 96. session sept 2014 Yann Caron (c) 2014 96 OpenFl  OpenFl : ➔ 2d uniquement ➔ massivement multiplateforme ➔ Fonctionne sur le langage Haxe (multiparadigme)  Créé par un Français ➔ Sur une VM NekoVM dont l'intermediate language est un langage de script (et pas du byteCode) ➔ Initialement inspiré par Flash
  • 97. session sept 2014 Yann Caron (c) 2014 97 NoJava – Alternative 2D  Sencyl : ➔ 2D, multiplateforme (iOS, Android, Flash, etc.) ➔ Basé sur OpenFl ➔ NoCode - Payant
  • 98. session sept 2014 Yann Caron (c) 2014 98 No Java – Alternative 3D  Unity 3D : ➔ 2D / 3D ➔ WYSIWYG Lua scripting ➔ Payant
  • 99. session sept 2014 Yann Caron (c) 2014 99 NoJava – Alternative 3D  ShiVa 3D : ➔ 3D multiplateforme ➔ WYSIWYD – Lua scripting ➔ Server MMO ➔ Gratuit
  • 100. session sept 2014 Yann Caron (c) 2014 100 Fin  Merci de votre attention  Des questions ?