Android Performance Tips

237be48129b762b31847d6167597366d?s=47 Romain Guy
November 12, 2013

Android Performance Tips

This presentation explains in detail some of the performance improvements provided by Android 4.4. You will also learn about tools and tips you can use to improve performance of your applications.

237be48129b762b31847d6167597366d?s=128

Romain Guy

November 12, 2013
Tweet

Transcript

  1. 3.

    #DV13 #AndroidPerf Lazy Measurement • Introduced in Android 4.4 -

    targetSdkVersion must be >= 19 • Views cache measured dimensions - Prior to 4.4 only the last measure was cached - In 4.4 all measures are cached until next requestLayout() • Can greatly reduce calls to onMeasure()
  2. 20.

    #DV13 #AndroidPerf Single measure cache • Works great in common

    cases • Breaks with multi-pass layouts - LinearLayout and weight - RelativeLayout - Custom layouts
  3. 42.

    #DV13 #AndroidPerf Multi-pass layouts • Siblings can cause extra onMeasure()

    calls • Nested multi-pass layouts can wreck havoc - A leaf View calling requestLayout() can relayout the entire tree! • Solution < 4.4 - Avoid multi-pass layouts - Use fewer Views • Solution >= 4.4 - Framework caches multiple measure pairs - Cache is cleared on requestLayout()
  4. 61.

    #DV13 #AndroidPerf With 4.4 ViewGroup View View measure(wSpec1, hSpec1) cached

    measures: (wSpec3, hSpec3) → (w3, h3) (wSpec1, hSpec1) → (w1, h1)
  5. 62.

    #DV13 #AndroidPerf With 4.4 ViewGroup View View measure(wSpec1, hSpec1) setDimensions(w1,

    h1) cached measures: (wSpec3, hSpec3) → (w3, h3) (wSpec1, hSpec1) → (w1, h1)
  6. 64.

    #DV13 #AndroidPerf Example RelativeLayout LinearLayout LinearLayout RelativeLayout Button TextView TextView

    TextView TextView RelativeLayout TextView TextView TextView requestLayout()
  7. 68.

    #DV13 #AndroidPerf DisplayList Reordering and Merging • Batches similar commands

    • Minimizes state changes • Minimizes GL operations
  8. 70.
  9. 79.

    #DV13 #AndroidPerf Without reordering & merging 576 OpenGL driver calls

    With reordering & merging 216 OpenGL driver calls
  10. 81.

    #DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by

    opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps
  11. 82.

    #DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by

    opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps Overdraw Window Background 1x
  12. 83.

    #DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by

    opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps Overdraw Container Background 2x
  13. 84.

    #DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by

    opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps Overdraw Button Button 2.1x Views
  14. 85.

    #DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by

    opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps
  15. 86.

    #DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by

    opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps Overdraw
  16. 87.

    #DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by

    opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps Overdraw Window Background 0x
  17. 88.

    #DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by

    opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps Overdraw Container Background 1x
  18. 89.

    #DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by

    opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps Overdraw Button Button 1.1x Views
  19. 90.

    #DV13 #AndroidPerf Bitmap Reuse • Reuse in 3.0 required Bitmaps

    of same size/configuration • Bitmaps can now be reconfigured/resized - Can create scratch buffer and load smaller bitmaps into it
  20. 98.

    procstats: command line $ adb shell dumpsys procstats com.google.android.apps.maps COMMITTED

    STATS FROM 2013-11-05-18-04-58: * com.google.android.apps.maps / u0a60: TOTAL: 1.1% Service: 1.1% (Cached): 99% (98MB-98MB-99MB/96MB-97MB-97MB over 7) Run time Stats: Screen Off / Norm / +1h19m25s22ms Screen On / Norm / +10m43s963ms TOTAL: +1h30m8s985ms Start time: 2013-11-05 18:04:58 Total elapsed time: +5h9m53s44ms (complete) libdvm.so chromeview
  21. 100.

    #DV13 #AndroidPerf Systrace • Introduced in Jellybean 4.1 • Recent

    improvements - More framework tags - More categories - Easier to launch - App-level tags
  22. 101.

    #DV13 #AndroidPerf Systrace • Introduced in Jellybean 4.1 • Recent

    improvements - More framework tags - More categories - Easier to launch - App-level tags Trace.beginSection("someLabel"); // stuff Trace.endSection();
  23. 106.

    #DV13 #AndroidPerf Bitmap Reuse mBitmapCache = Bitmap.createBitmap(500, 500, Bitmap.Config.ARGB_8888); mBitmapOptions.inBitmap

    = mBitmapCache; mBitmapOptions.inSampleSize = 1; Bitmap newBitmap; if (mCheckBox.isChecked()) { newBitmap = BitmapFactory.decodeResource( getResources(), images[index], mBitmapOptions); } else { newBitmap = BitmapFactory.decodeResource( getResources(), images[index]); } mImageView.setImageBitmap(newBitmap);
  24. 107.

    #DV13 #AndroidPerf Atlas • Popular in games, on web sites,

    etc… - Also called “sprite sheets“ • Can increase performance - Reduce number of OpenGL driver calls - Reduce number of GPU state changes - Better merging of draw calls
  25. 110.

    #DV13 #AndroidPerf Loading the atlas 1/4 • res/raw/atlas.txt • Format:

    atlas_name ImageName,left,top,right,bottom ImageName,left,top,right,bottom ImageName,left,top,right,bottom
  26. 111.

    #DV13 #AndroidPerf Loading the atlas 2/4 atlas Mountain,1,1,301,201 Gecko,302,1,602,201 Seahorse,603,1,903,201

    Camera,904,1,1204,201 Fish,1205,1,1505,201 Plasma,1,202,301,402 Grass,302,202,602,402 Photographer,603,202,903,402 Lights,904,202,1204,402 Flower,1205,202,1505,402
  27. 112.

    #DV13 #AndroidPerf Loading the atlas 3/4 String line = reader.readLine();

    Resources res = getContext().getResources(); int atlasId = res.getIdentifier(line, "drawable", getContext().getPackageName()); mAtlas = BitmapFactory.decodeResource(res, atlasId);
  28. 113.

    #DV13 #AndroidPerf Loading the atlas 3/4 String line = reader.readLine();

    Resources res = getContext().getResources(); int atlasId = res.getIdentifier(line, "drawable", getContext().getPackageName()); mAtlas = BitmapFactory.decodeResource(res, atlasId);
  29. 114.

    #DV13 #AndroidPerf Loading the atlas 3/4 String line = reader.readLine();

    Resources res = getContext().getResources(); int atlasId = res.getIdentifier(line, "drawable", getContext().getPackageName()); mAtlas = BitmapFactory.decodeResource(res, atlasId);
  30. 115.

    #DV13 #AndroidPerf Loading the atlas 4/4 static class Entry {

    String name; final Rect src = new Rect(); } while ((line = reader.readLine()) != null) { String[] fields = line.split(","); Entry entry = new Entry(); entry.name = fields[0]; entry.src.set(parseInt(fields[1]), parseInt(fields[2]), parseInt(fields[3]), parseInt(fields[4])); mEntries.add(entry); }
  31. 116.

    #DV13 #AndroidPerf Drawing the atlas protected void onDraw(Canvas canvas) {

    final int count = mEntries.size(); for (int i = 0; i < count; i++) { Entry entry = mEntries.get(i); int x = computeX(entry); int y = computeY(entry); mDst.set(x, y, x + entry.src.width(), y + entry.src.height()); canvas.drawBitmap(mAtlas, entry.src, mDst, null); } }
  32. 117.

    #DV13 #AndroidPerf Drawing the atlas protected void onDraw(Canvas canvas) {

    final int count = mEntries.size(); for (int i = 0; i < count; i++) { Entry entry = mEntries.get(i); int x = computeX(entry); int y = computeY(entry); mDst.set(x, y, x + entry.src.width(), y + entry.src.height()); canvas.drawBitmap(mAtlas, entry.src, mDst, null); } }
  33. 118.

    #DV13 #AndroidPerf Drawing the atlas protected void onDraw(Canvas canvas) {

    final int count = mEntries.size(); for (int i = 0; i < count; i++) { Entry entry = mEntries.get(i); int x = computeX(entry); int y = computeY(entry); mDst.set(x, y, x + entry.src.width(), y + entry.src.height()); canvas.drawBitmap(mAtlas, entry.src, mDst, null); } }
  34. 119.

    #DV13 #AndroidPerf Atlas tips 1/2 • 1px transparent border around

    entries - Allows proper bilinear filtering - For scaling, rotation, perspective, etc. • Watch out for max texture size - Especially at xxhdpi - 2048x2048 is common - 4096x4096 on recent devices
  35. 121.

    #DV13 #AndroidPerf Atlas tips 2/2 • Disable blending for opaque

    entries • Use a Paint with the SRC blend mode - mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)) • Store this information in atlas file - Name,left,top,right,bottom,1 // 1=opaque, 0= transparent
  36. 122.

    #DV13 #AndroidPerf Layout • Don’t use multi-pass layouts at the

    top of the tree - Very expensive • LinearLayout is multi-pass… sometimes - For children with a layout_weight • RelativeLayout is always multi-pass
  37. 123.

    #DV13 #AndroidPerf Tips for LinearLayout • Vertical layouts - Set

    height to 0dp for children with a weight • Horizontal layouts - Set width to 0dp for children with a weight - And set baselineAligned=”false” on LinearLayout • These tips don’t always apply
  38. 126.

    Non-Rectangular Clipping 59 @Override protected void onDraw(Canvas canvas) { //

    Keep the jellybeans canvas.clipRect(l, t, r, b); // Rotate the jar canvas.rotate(-30.0f, pX, pY); // Draw the jar canvas.drawBitmap(mJellyBeans, x, y, null); }
  39. 127.

    60

  40. 128.
  41. 130.
  42. 131.

    60

  43. 132.

    61 @Override protected void onDraw(Canvas canvas) { // Rotate the

    jar canvas.rotate(-30.0f, pX, pY); // Keep the jellybeans canvas.clipRect(l, t, r, b); // Draw the jar canvas.drawBitmap(mJellyBeans, x, y, null); }
  44. 133.

    62

  45. 135.
  46. 136.
  47. 137.

    62

  48. 140.

    #DV13 #AndroidPerf Don’t Update Layers • Avoid invalidating layered views/containers

    - Don’t change view or child views, remove children, add children, ... view.setLayerType(View.LATER_TYPE_HARDWARE, null); // run animation view.setLayerType(View.LAYER_TYPE_NONE, null); // or view.animate().alpha(0).withLayer();
  49. 143.

    #DV13 #AndroidPerf For More Information • Google I/O talks •

    Parleys.com talks • Devbytes on YouTube Chet graphics-geek.blogspot.com google.com/+ChetHaase @chethaase Romain: curious-creature.org google.com/+RomainGuy @romainguy