Th 0230 turbo_chargeyourui-howtomakeyourandroidu_ifastandefficient

  • 174 views
Uploaded on

 

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
174
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
6
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Turbo-charge your UI Romain Guy May 29, 2009
  • 2. Disclaimer
  • 3. 4 Agenda • Adapters • Backgrounds and images • Drawing and invalidating • Views and layouts • Memory allocations
  • 4. 5 Agenda • Adapters • Backgrounds and images • Drawing and invalidating • Views and layouts • Memory allocations
  • 5. 6 Adapters • Awesome • Painful • Do you even know how ListView works?
  • 6. 7 Man in the middle
  • 7. 8 Gimme views • For each position – Adapter.getView() • A new View is returned – Expensive • What if I have 1,000,000 items?
  • 8. Adapter 9 Getting intimate with ListView Item 2 Item 3 Item 4 Item 5 Item 6 Item 7 Recycler Type 1 Type 2 Type n Item 1 Item 8
  • 9. 10 Don’t public View getView(int position, View convertView, ViewGroup parent) { View item = mInflater.inflate(R.layout.list_item_icon_text, null); ((TextView) item.findViewById(R.id.text)).setText(DATA[position]); ((ImageView) item.findViewById(R.id.icon)).setImageBitmap( (position & 1) == 1 ? mIcon1 : mIcon2); return item; }
  • 10. 11 Do public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = mInflater.inflate(R.layout.item, null); } ((TextView) convertView.findViewById(R.id.text)).setText(DATA[position]); ((ImageView) convertView.findViewById(R.id.icon)).setImageBitmap( (position & 1) == 1 ? mIcon1 : mIcon2); return convertView; }
  • 11. 12 Even better static class ViewHolder { TextView text; ImageView icon; }
  • 12. 13 Even better 1 public View getView(int position, View convertView, ViewGroup parent) { 2 ViewHolder holder; 3 4 if (convertView == null) { 5 convertView = mInflater.inflate(R.layout.list_item_icon_text, null); 6 7 holder = new ViewHolder(); 8 holder.text = (TextView) convertView.findViewById(R.id.text); 9 holder.icon = (ImageView) convertView.findViewById(R.id.icon); 10 11 convertView.setTag(holder); 12 } else { 13 holder = (ViewHolder) convertView.getTag(); 14 } 15 16 holder.text.setText(DATA[position]); 17 holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2); 18 19 return convertView; 20 }
  • 13. 14 Is it worth it? 0 10 20 30 40 Dumb Recycling views ViewHolder Frames per second
  • 14. 15 Agenda • Adapters • Backgrounds and images • Drawing and invalidating • Views and layouts • Memory allocations
  • 15. 16 Don’t be greedy • Background drawables always fit the view – Stretching may occur • Runtime scaling is expensive
  • 16. 17 How expensive? 0 12.5 25 37.5 50 Auto-scaled Pre-scaled Frames per second
  • 17. Pre-scaling is easy 18 // Rescales originalImage to the size of view using // bitmap filtering for better results originalImage = Bitmap.createScaledBitmap( originalImage, // bitmap to resize view.getWidth(), // new width view.getHeight(), // new height true); // bilinear filtering
  • 18. Window backgrounds • Sometimes unnecessary – Top-level opaque view – layout_width=fill_parent – layout_height=fill_parent • Expensive to draw • Dumb rendering engine – (And it’s my fault) 19
  • 19. Removing the background 20 <!-- res/values/styles.xml --> <resources> <style name="Theme.NoBackground" parent="android:Theme"> <item name="android:windowBackground">@null</item> </style> </resources>
  • 20. Removing the background 21 <activity android:name="MyApplication" android:theme="@style/NoBackgroundTheme"> <!-- intent filters and stuff --> </activity>
  • 21. 22 What do I get? 0 14 28 42 56 With background No background Frames per second
  • 22. 23 Good news!
  • 23. 24 Agenda • Adapters • Backgrounds and images • Drawing and invalidating • Views and layouts • Memory allocations
  • 24. Redraw efficiently • invalidate() – So easy – So expensive • Dirty regions – invalidate(Rect) – invalidate(left, top, right, bottom) 25
  • 25. Demo, invalidating Home
  • 26. 27 Just do it 0 10 20 30 40 50 invalidate() invalidate(Rect) invalidate(int, int, int, int) Frames per second
  • 27. 28 Agenda • Adapters • Backgrounds and images • Drawing and invalidating • Views and layouts • Memory allocations
  • 28. 29 Fewer is better • Many views – Longer startup time – Slower measurement – Slower layout – Slower drawing • Deep hierarchies – StackOverflowException – Slow... slow... slow...
  • 29. HierarchyViewer
  • 30. 31 A few solutions • TextView’s compound drawables • ViewStub • <merge /> • RelativeLayout • Custom views • Custom layouts
  • 31. 32 Compound drawables <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/icon" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello" /> </LinearLayout> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello" android:drawableLeft="@drawable/icon" />
  • 32. 33 ViewStub
  • 33. 34 ViewStub
  • 34. 35 ViewStub <ViewStub android:id="@+id/stub_import" android:inflatedId="@+id/panel_import" android:layout="@layout/progress_overlay" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" />
  • 35. 36 Inflating a ViewStub findViewById(R.id.stub_import).setVisibility(View.VISIBLE); // or View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
  • 36. 37 <merge />
  • 37. 38 <merge /> <!-- The merge tag must be the root tag --> <merge xmlns:android="http://schemas.android.com/apk/res/android"> <!-- Content --> </merge>
  • 38. 39 RelativeLayout • Powerful • Replace linear layouts – A horizontal LinearLayout in a vertical one – Or the other way around • Sometimes hard to use – (And it’s all my fault)
  • 39. 40 Custom views
  • 40. 41 Custom views class CustomView extends View { public CustomView(Context context) { super(context); } @Override protected void onDraw(Canvas canvas) { } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(100, 100); } }
  • 41. 42 Custom layouts
  • 42. 43 Custom layouts public class GridLayout extends ViewGroup { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int count = getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); // Define measurement spec of each child child.measure(childWidthSpec, childheightSpec); } setMeasuredDimension(widthSpecSize, heightSpecSize); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = getChildCount(); for (int i = 0; i < count; i++) { View child = getChildAt(i); if (child.getVisibility() != GONE) { // Compute position of each child child.layout(left, top, right, bottom); } } } }
  • 43. 44 Agenda • Adapters • Backgrounds and images • Drawing and invalidating • Views and layouts • Memory allocations
  • 44. 45 DO NOT ALLOCATE MEMORY • As much as you can • GC – Stops the world – Slow (~x00 ms)
  • 45. 46 Performance sensitive paths Measurement onMeasure() Layout onLayout() Drawing draw() dispatchDraw() onDraw() Events handling dispatchTouchEvent() onTouchEvent() Adapters getView() bindView()
  • 46. 47 Fail fast int prevLimit = -1; try { // Limit the number of allocated objects prevLimit = Debug.setAllocationLimit(0); // Execute code that should not perform // any allocation } finally { Debug.setAllocationLimit(prevLimit); }
  • 47. Demo, allocation tracker
  • 48. 49 Manage your objects • SoftReferences – Excellent for memory caches • WeakReferences – Avoids memory leaks
  • 49. 50 Simple cache private final HashMap<String, SoftReference<T>> mCache; public put(String key, T value) { mCache.put(key, new SoftReference<T>(value)); } public T get(String key, ValueBuilder builder) { T value = null; SoftReference<T> reference = mCache.get(key); if (reference != null) { value = reference.get(); } // Not in cache or gc'd if (value == null) { value = builder.build(key); mCache.put(key, new SoftReference<T>(value)); } return value; }
  • 50. 51 Resources • http://d.android.com • http://source.android.com • http://android.git.kernel.org • http://code.google.com/p/apps-for-android • http://code.google.com/p/shelves
  • 51. Q&A