Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Optimizing UI Performance in Android Apps

Optimizing UI Performance in Android Apps

98c2d4d449d87a611778e2ff107f3877?s=128

Sriram Ramani

November 29, 2013
Tweet

Transcript

  1. Optimizing UI Performance in Android Apps Sriram Ramasubramanian @sriramramani

  2. “a lot snappier now” Firefox for Android “starts up quicker”

    “best overall browser experience” “tablet version was "Buttery" Smooth!”
  3. Photo application Card UI ListView of photos Clickable areas in

    each list item Shutter
  4. None
  5. Tools

  6. Number of times a pixel on the screen is touched

    1x Blue 2x Green 3x Red 4+ Deep Red Show GPU Overdraw
  7. An aggregated counter for overall overdraw ~2x is good Debug

    GPU Overdraw
  8. Time taken to draw each frame Green line is 16ms

    mark Blue update lists Red process lists Yellow swap buffers Profile GPU Rendering
  9. Time taken to draw each frame Green line is 16ms

    mark Blue update lists Red process lists Yellow swap buffers Profile GPU Rendering
  10. Profile GPU Rendering Hey bro! Why so slow?

  11. Systrace.py

  12. Droid Inspector http://sriramramani.com/droidinspector

  13. None
  14. None
  15. None
  16. None
  17. None
  18. import com.sriramramani.droid.inspector.server.ViewServer; ! public class MyActivity extends Activity { !

    @Override public void onCreate(Bundle ofJoy) { super.onCreate(ofJoy); ViewServer.get(this).addWindow(this); } ! @Override public void onDestroy() { super.onDestroy(); ViewServer.get(this).removeWindow(this); } ! @Override public void onResume() { super.onResume(); ViewServer.get(this).setFocusedWindow(this); } }
  19. Techniques

  20. Remove Overdraw 1

  21. None
  22. None
  23. Redundant Backgrounds

  24. <!—— Problem ——> <style name="Theme.Holo.Light" parent=“Theme.Light”> <item name=“windowBackground"> @android:drawable/screen_background_selector_light </item>

    </style> ! ! ! ! ! ! // Solution @Override public void onWindowFocusChanged(boolean hasFocus) { ! super.onWindowFocusChanged(hasFocus); ! // Reset the background getWindow().setBackgroundDrawable(null); }
  25. Redundant Backgrounds

  26. Redundant Backgrounds

  27. Redundant Backgrounds

  28. Redundant Backgrounds

  29. Reduce Views 2

  30. PhotoItemView

  31. Compound Drawables Merging an ImageView (icon) with the TextView (label)

    And the drawables support states! Accompanying Label
  32. Compound Drawables Merging an ImageView (icon) with the TextView (label)

    And the drawables support states! Accompanying Label
  33. Compound Drawables

  34. Compound Drawables

  35. Compound Drawables

  36. <LinearLayout android:layout_width=“match_parent” android:layout_height=“match_parent”> ! <ImageView android:layout_width=“24dp” android:layout_height=“24dp” android:src=“@drawable/icon”/> ! <TextView

    android:layout_width=“0dip” android:layout_height=“match_parent” android:paddingLeft=“10dp” android:text=“Label”/> ! </LinearLayout>
  37. <TextView android:layout_width=“match_parent” android:layout_height=“match_parent” android:drawableLeft=“@drawable/icon” android:drawablePadding=“10dp” android:text=“Label”/> ! ! ! !

    textView.setCompoundDrawables(left, top, right, bottom); ! textView.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom); ! textView.setCompoundDrawablesRelative(start, top, end, bottom);
  38. Similar to <span/> element in HTML ForegroundColorSpan
 BackgroundColorSpan
 TextAppearanceSpan
 ImageSpan


    UnderlineSpan
 URLSpan Spannable String
  39. SpannableStringBuilder builder = new SpannableStringBuilder(_text_); ! ForegroundColorSpan foreground = new

    ForegroundColorSpan(0xFFFF0000); ! builder.setSpan(foreground, startIndex, endIndex, Spanned.SPAN_INCLUSIVE_INCLUSIVE); ! mTextView.setText(builder, BufferType.SPANNABLE);
  40. Spannable String

  41. Spannable String

  42. Spannable String

  43. Manipulate the Canvas 3

  44. Redundant Backgrounds

  45. Redundant Backgrounds

  46. Porter-Duff Alpha compositing Combining multiple images into a single, final

    image Determines how to apply a SRC on a DST
  47. Porter-Duff SRC_OVER

  48. Porter-Duff DST_OVER

  49. Porter-Duff DST_IN

  50. Porter-Duff DST_OUT

  51. Porter-Duff DST SRC DST_IN

  52. Porter-Duff DST SRC DST_IN

  53. @Override public void draw(Canvas canvas) { canvas.save(); ! // Ask

    parent to draw. This is the DST. super.draw(canvas); ! // Create an off-screen bitmap. Bitmap mask = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); // Draw the path on the bitmap. This is the SRC. (new Canvas(mask)).drawPath(mPath, mPaint); // Draw the bitmap containing the path, over the actual canvas. mPaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); canvas.drawBitmap(mask, 0, 0, mPaint); // Reset paint, as it will be used again to draw a path on a bitmap. mPaint.setXfermode(null); ! canvas.restore(); }
  54. Porter-Duff

  55. Porter-Duff

  56. Shaders Horizontal spans of colors during drawing Added to the

    Paint of the Canvas Analogous to a paint brush in Photoshop Paint with a color is the simplest shader
  57. Shaders Bitmap Shader Path Result

  58. public void setImage(Bitmap bitmap) { BitmapShader bitmapShader = new BitmapShader(mBitmap,

    Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); mPaint.setShader(bitmapShader); } ! ! ! ! ! @Override public void draw(Canvas canvas) { // Draw the bitmap. canvas.drawPath(mPath, mPaint); }
  59. Shaders Shader A Shader B Porter-Duff Compose Shader

  60. Shaders Bitmap Shader Linear Gradient DST_IN Porter-Duff

  61. public void setImage(Bitmap bitmap) { BitmapShader bitmapShader = new BitmapShader(mBitmap,

    Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); ! LinearGradient gradient = new LinearGradient(0, 0, 0, bitmap.getHeight(), 0xFF000000, 0x0, Shader.TileMode.CLAMP); // bitmap is the DST. gradient is the SRC. mPaint.setShader(new ComposeShader(bitmapShader, gradient, PorterDuff.Mode.DST_IN)); } ! ! @Override public void draw(Canvas canvas) { // Draw the bitmap. canvas.drawPaint(mPaint); }
  62. Shaders

  63. Custom Views Simple layouts can draw themselves Override onMeasure() and

    onDraw()
  64. @Override protected void onMeasure(Canvas canvas) { // Ask the parent

    to set the padding. super.onMeasure(widthMeasureSpec, heightMeasureSpec); ! int children = (mContacts == null) ? 0 : mContacts.length; ! int eachChildWidth = mChildSize + (2 * mChildMargin); ! int width = getPaddingLeft() + getPaddingRight() + (children * eachChildWidth); ! setMeasuredDimension(width, getMeasuredHeight()); }
  65. @Override protected void onDraw(Canvas canvas) { canvas.save(); ! // Translate

    the canvas. canvas.translate(getPaddingLeft(), ((getHeight() - mChildSize)/2)); ! final int length = mShaders.length; ! for (int i = 0; i < length; i++) { canvas.translate(mChildMargin, 0); ! // Set the child shader. mPaint.setShader(mShaders[i]); ! canvas.drawRoundRect(mChildBounds, mChildCorner, mChildCorner, mPaint); ! canvas.translate(mChildSize + mChildMargin, 0); } ! canvas.restore(); }
  66. Compare Results

  67. None
  68. None
  69. PhotoItemView

  70. 3.86x 1.09x

  71. before after

  72. before after before

  73. Systrace.py

  74. That’s all folks! ! http://sriramramani.wordpress.com http://sriramramani.com/droidinspector http://github.com/sriramramani/Shutter