1. Cyril Mottier
@cyrilmottier
http://www.cyrilmottier.com
Optimisations générales
sous Android et GreenDroid
Concevoir des applications réactives, fluides et
facile d’utilisation
19. Conclusion - 2/2
• GC non contrôlable
• Oubliez System.gc() !
• Voyez le GC comme une entité indépendante
20. Conclusion - 2/2
• GC non contrôlable
• Oubliez System.gc() !
• Voyez le GC comme une entité indépendante
• Pensez différemment ...
• Utilisez les types primitifs
• Minimisez la création d’objets
• Réutilisez les objets
21. Conclusion - 2/2
• GC non contrôlable
• Oubliez System.gc() !
• Voyez le GC comme une entité indépendante
• Pensez différemment ...
• Utilisez les types primitifs
• Minimisez la création d’objets
re !
• Réutilisez les objets
sa i
é c es
S in
23. Le langage Java
• Introduit en 1996
• Langage haut-niveau
• Langage objet fortement typé
• Pas/peu de gestion mémoire
• Syntaxe avancée (foreach, etc.)
• Apparente simplicité
• Cache des points d’ombre
24. Autoboxing
public int factBad(int arg) {
if (arg < 0) {
throw new ArithmeticException("arg must be a positive integer");
}
Integer result = 1;
for (int i = 2; i <= arg; i++) {
result *= i;
}
return result;
}
25. Autoboxing
public int factBad(int arg) {
if (arg < 0) {
throw new ArithmeticException("arg must be a positive integer");
}
Integer result = 1;
for (int i = 2; i <= arg; i++) {
result *= i;
}
return result;
}
équivaut à
public int factBad2(int arg) {
if (arg < 0) {
throw new ArithmeticException("arg must be a positive integer");
}
Integer result = new Integer(1);
for (int i = 2; i <= arg; i++) {
result = new Integer(result.intValue() * i);
}
return result.intValue();
}
26. Autoboxing
• Utilisez les types primitifs
• byte, short, int, long
• float, double
• boolean, char
public int factGood(int arg) { public int factGood2(int arg) {
if (arg < 0) { if (arg < 0) {
throw new ArithmeticException(); throw new ArithmeticException();
} }
int result = 1; return (arg == 0) ? 1 :
for (int i = 2; i <= arg; i++) { arg * factGood2(arg - 1);
result *= i; }
}
return result;
}
30. Temporaires contre statiques - 1/2
public boolean intersect(int left, int top, int right, int bottom) {
return intersect(new Rect(left, top, right, bottom));
}
public abstract boolean intersect(Rect rect);
31. Temporaires contre statiques - 1/2
public boolean intersect(int left, int top, int right, int bottom) {
return intersect(new Rect(left, top, right, bottom));
}
public abstract boolean intersect(Rect rect);
Préférez les statiques aux temporaires ...
private static final Rect sRect = new Rect();
public boolean intersect(int left, int top, int right, int bottom) {
sRect.set(left, top, right, bottom);
return intersect(sRect);
}
public abstract boolean intersect(Rect rect);
32. Temporaires contre statiques - 2/2
• Technique dédiée aux méthodes critiques
• onDraw(), onMeasure(), onLayout(), getView(), etc.
• Paint
• Rect
• Point
• Classes utilitaires
• Random
• Méthodes à retour via arguments
• Location.distanceBetween( ..., float[] results)
33. Les arguments variables
public void main() {
varargs(1, 2, 3);
}
public abstract void varargs(int ... args);
34. Les arguments variables
public void main() {
varargs(1, 2, 3);
}
public abstract void varargs(int ... args);
est équivalent à la création d’un tableau ...
public void main() {
varargs(new int[]{1, 2, 3});
}
public abstract void varargs(int ... args);
35. Les itérateurs - 1/2
public void iteratorBad(List<T> list) {
for (T obj : list) {
// ...
}
}
36. Les itérateurs - 1/2
public void iteratorBad(List<T> list) {
for (T obj : list) {
// ...
}
}
Revient à créer un Iterator
public void iteratorBad(List<T> list) {
T obj;
for (Iterator<T> i = list.iterator(); i.hasNext(); obj = i.next()) {
// ...
}
}
37. Les itérateurs - 2/2
• Utilisez la syntaxe foreach :
• Facile à lire
• Optimisée
• Limitez la casse !
public void iteratorGood(List<T> list) {
if (list != null && list.size() != 0) {
for (T obj : list) {
// ...
}
}
}
39. Les Strings - 1/3
private static final String SLOGAN = "This" + " " + "conference" + " " + "is" + "
" + "awesome";
public String getSlogan() {
return SLOGAN;
}
est résolu à la compilation par
private static final String SLOGAN = "This conference is awesome";
public String getSlogan() {
return "This conference is awesome";
}
40. Les Strings - 2/3
public String concatBad(String[] strings) {
String result = null;
for (String s : strings) {
result += s;
}
return result;
}
41. Les Strings - 2/3
public String concatBad(String[] strings) {
String result = null;
for (String s : strings) {
result += s;
}
return result;
}
entraine l’instanciation d’un StringBuilder
public String concatBad(String[] strings) {
String result = null;
for (String s : strings) {
result = new StringBuilder(result).append(s).toString();
}
return result;
}
42. Les Strings - 3/3
public String concatCorrect(String[] strings) {
StringBuilder result = new StringBuilder();
for (String s : strings) {
result.append(s);
}
return result.toString();
}
43. Les Strings - 3/3
public String concatCorrect(String[] strings) {
StringBuilder result = new StringBuilder();
for (String s : strings) {
result.append(s);
}
return result.toString();
}
Ou encore mieux ...
private static StringBuilder sStringBuilder = new StringBuilder();
public String concatGood(String[] strings) {
sStringBuilder.setLength(0);
for (String s : strings) {
sStringBuilder.append(s);
}
return sStringBuilder.toString();
}
44. Quelques astuces
• Réutilisez les objets
• ViewHolder et convertView avec les ListViews/Adapters
• Handler.obtainMessage() / Message.obtain()
• Classes dans android.util :
• PoolableManager, Pool, Poolable, Pools, FinitePool, SynchronizedPool
• Evitez la création d’objets
• CharArrayBuffer avec les Cursors
• SparseArray
49. Présentation
• Un maître mot : MINIMISATION !
• Moins de vues équivaut à :
• measure() plus rapide
• layout() plus rapide
• draw() plus rapide
50. Présentation
• Un maître mot : MINIMISATION !
• Moins de vues équivaut à :
• measure() plus rapide
• layout() plus rapide
• draw() plus rapide
• Trop de vues :
• OutOfMemoryException
• LayoutInflater.inflate() long
51. Présentation
• Un maître mot : MINIMISATION !
• Moins de vues équivaut à :
• measure() plus rapide
• layout() plus rapide
• draw() plus rapide
• Trop de vues :
• OutOfMemoryException
• LayoutInflater.inflate() long
• Préférez la largeur à la profondeur
52. Le cas du débutant ... - 1/2
• Création d’un nouveau projet
• Utilisation du layout « exemple »
<?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">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
</LinearLayout>
67. Vues personnalisées
public class CustomView extends View {
public CustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onDraw(Canvas canvas) {
// Dessin de la vue
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Définition de la taille de la vue en fonction des spécifications
setMeasuredDimension(100, 100);
}
}
68. Layouts personnalisées
public class CustomLayout extends ViewGroup {
public CustomLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Définition de la taille de la vue en fonction des spécifications et
// des dimensions des vues filles
// child.measure(widthMeasureSpec, heightMeasureSpec)
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int d) {
// Positionnement et dimensionnement de l'ensemble des vues filles
// child.layout(left, top, right, int bottom)
}
}
75. Présentation
• Le système graphique Android est single threaded
• Limitez l’impact sur le UI thread !
76. Présentation
• Le système graphique Android est single threaded
• Limitez l’impact sur le UI thread !
• Conséquences nombreuses
• Animations saccadées
• ANR
• Utilisateur mécontent
• Application désinstallée / critiquée ...
90. Un triste constat
• Ressenti général médiocre
• Peu de qualité
• Design / ergo antagonistes
• Framework difficile ?
• Trop ouvert
• Pas d’aide UI/UX
91. Pourquoi GreenDroid ?
• La naissance de GreenDroid :
• Challenge, opensource, factorisation, etc.
• Make Android Market a better place
• La philosophie :
• Make Android development consistent and easier
100. Utilisation
• S’assurer que votre application est une 1
GDApplication :
greendroid.app.GDApplication
2
•
• Votre propre GDApplication
3
4
101. Utilisation
• S’assurer que votre application est une 1
GDApplication :
greendroid.app.GDApplication
2
•
• Votre propre GDApplication
<application
android:icon="@drawable/icon"
android:label="@string/app_name"
android:name="greendroid.app.GDApplication"
3
android:theme="@style/Theme.GreenDroid">
<!-- ... -->
</application> 4
102. Régles importantes
• Ne modifiez pas GreenDroid !
• Utilisation de la notion d’héritage :
• Java pour les classes
• XML pour les styles / thèmes
• Pas possible de faire autrement ?
• fork
• patch
• feature request
• N’hésitez pas à patcher / participer !
104. ActionBar - 1/2
• Pattern ergonomique :
• Affiche le titre de l’écran courant
• Donne accès à des actions
• Permet le retour à l’écran principal
• Présente l’état courant :
• ProgressBar présentant le chargement
• Couleur de l’ActionBar fonction du contenu
• ...
105. ActionBar - 2/2
public class ActionBarActivity extends GDActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setActionBarContentView(R.layout.text);
addActionBarItem(Type.Locate, R.id.action_bar_locate);
}
@Override
public boolean onHandleActionBarItemClick(ActionBarItem item, int position) {
switch (item.getItemId()) {
case R.id.action_bar_locate:
// Do something
break;
default:
return super.onHandleActionBarItemClick(item, position);
}
return true;
}
}