Devoxx France 2012 – Android, Graphism and Performance
To begin, Romain is speaking about threads in Android (subject that I am starting to know well) by saying us to not block the main thread, also known as UI thread because user interface operations must run inside it. To avoid blocking it, you must use the Handler class and its post(Runnable) method or use the AsyncTask class (equivalent to the SwingWorker class for Swing). About the AsyncTask class, Romain indicates it’s possible to call the executeOnExecutor method to use a custom thread pool. Since Android 3, 2 standard Executors exist : AsyncTask.SERIAL_EXECUTOR and AsyncTask.THREAD_POOL_EXECUTOR.
Then he advises us to activate the strict mode to verify an application has good behaviours (see the StrictMode documentation). It verifies in particular you are executing operations (inputs/outputs, graphical interface modification …) in the good thread (see my other article on the subject).
On the side of memory and processor usage, the creation of a View is very expensive, as well as inflation of the xml describing it. A TextView costs 800 bytes of memory.
About layouts, you must use them the least possible and avoid as much as possible the LinearLayout, especially if it’s associated with the android:layout_weight attribute.
He advises us to apply the following rules :
- Avoid stacking layouts (it can give a stackoverflow if there is too much levels) as much as possible.
- Use a unique layout in the view, the GridLayout.
- Think about overloading views in order they do only what you need, unlike standard views.
- Avoid calling the View.requestLayout() method. However, it’s automatically called when text size of a TextView has changed.
- Remove new as much as possible, especially in onDrawXxx methods from View class
He continues by presenting the ViewStub component, to use when a view is displayed from time to time. Its main properties are id corresponding to the stub identifier and inflatedid representing the associated view identifier. When the ViewStub.inflate method is called, the stub is removed from the hierarchy of views and replaced by the associated view.
About tools, he presents traceview to measure performances, hierarchyviewer to see views loaded in memory (especially the allocation tracker tab visible in the eclipse plugin) and lint to analyze layouts and source code.
To analyze memory used by an application, there is the adb shell dumpsys meminfo command. The first column, titled Pss is the most interesting one. The line titled other dev corresponds to memory used by the graphical chipset, especially for textures. For more informations on resource used by the graphical chipset, you can type adb shell dumpsys gfxinfo.
Then, Romain speaks about hardware acceleration for graphical rendering. First of all there is the android:hardwareAccelerated attribute, available since version 14 of Android API, which can be positioned at many levels : application, activity, window, view. It’s possible to combine different levels for finer tuning. Here is some other optimization technics he gives us :
- Prefer using methods with parameters (invalidate(Rect), invalidate(int, int, int, int)) instead of invalidate() method from View class
- Instead of a loop with a call to Canvas.drawLine(float, float, float, float, Paint), it’s preferable to call one of the Canvas.drawLines methods (drawLines(float, Paint), drawLines(float, int, int, Paint))
- Group graphical primitive calls by type : all drawText, all drawLine(float, float, float, float, Paint) …
It’s possible to specify the type of layer for a view by calling the View.setLayerType method. Its first parameter can take following values :
- LAYER_TYPE_SOFTWARE : software rendering in a bitmap, expensive because it uses the main memory and the graphic chipset’s memory but it can solve some problems with hardware rendering.
- LAYER_TYPE_HARDWARE : rendering by the graphic chipset. So, it’s faster and only one memory allocation is done.
Layers must be used carefully because they are expensive in term of memory and processor time.
About animations, it’s possible to animate properties (used for graphical rendering) inside an interval of values. To make it works, a getter and a setter are necessary for each property to animate. When it’s possible, standard properties (like View.x) must be used. These are more optimized because their animation doesn’t use the reflection API. At the end of the animation, you must not forget to remove the layer by calling setLayerType(LAYER_TYPE_NONE).
During the session of questions, I asked him how to improve performances of vertical scrolling in lists (ListView) with a lot of elements.
He replied performances doesn’t depend on number of elements and advised me to use the traceview tool to analyse performances. He also underlined that until Android 2.3 (included), there is no synchronisation with VSync, which can impact performances while scrolling a list.
Thanks Romain for all these informations about Android ! I have learned a lot of things