0
Turbo-charge your UI
Romain Guy
May 29, 2009
Disclaimer
4
Agenda
• Adapters
• Backgrounds and images
• Drawing and invalidating
• Views and layouts
• Memory allocations
5
Agenda
• Adapters
• Backgrounds and images
• Drawing and invalidating
• Views and layouts
• Memory allocations
6
Adapters
• Awesome
• Painful
• Do you even know how ListView works?
7
Man in the middle
8
Gimme views
• For each position
– Adapter.getView()
• A new View is returned
– Expensive
• What if I have 1,000,000 item...
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
It...
10
Don’t
public View getView(int position, View convertView, ViewGroup parent) {
View item = mInflater.inflate(R.layout.li...
11
Do
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mIn...
12
Even better
static class ViewHolder {
TextView text;
ImageView icon;
}
13
Even better
1 public View getView(int position, View convertView, ViewGroup parent) {
2 ViewHolder holder;
3
4 if (conv...
14
Is it worth it?
0
10
20
30
40
Dumb Recycling views ViewHolder
Frames per second
15
Agenda
• Adapters
• Backgrounds and images
• Drawing and invalidating
• Views and layouts
• Memory allocations
16
Don’t be greedy
• Background drawables always fit the view
– Stretching may occur
• Runtime scaling is expensive
17
How expensive?
0
12.5
25
37.5
50
Auto-scaled Pre-scaled
Frames per second
Pre-scaling is easy
18
// Rescales originalImage to the size of view using
// bitmap filtering for better results
original...
Window backgrounds
• Sometimes unnecessary
– Top-level opaque view
– layout_width=fill_parent
– layout_height=fill_parent
...
Removing the background
20
<!-- res/values/styles.xml -->
<resources>
<style name="Theme.NoBackground" parent="android:The...
Removing the background
21
<activity
android:name="MyApplication"
android:theme="@style/NoBackgroundTheme">
<!-- intent fi...
22
What do I get?
0
14
28
42
56
With background No background
Frames per second
23
Good news!
24
Agenda
• Adapters
• Backgrounds and images
• Drawing and invalidating
• Views and layouts
• Memory allocations
Redraw efficiently
• invalidate()
– So easy
– So expensive
• Dirty regions
– invalidate(Rect)
– invalidate(left, top, righ...
Demo, invalidating Home
27
Just do it
0
10
20
30
40
50
invalidate() invalidate(Rect) invalidate(int, int, int, int)
Frames per second
28
Agenda
• Adapters
• Backgrounds and images
• Drawing and invalidating
• Views and layouts
• Memory allocations
29
Fewer is better
• Many views
– Longer startup time
– Slower measurement
– Slower layout
– Slower drawing
• Deep hierarc...
HierarchyViewer
31
A few solutions
• TextView’s compound drawables
• ViewStub
• <merge />
• RelativeLayout
• Custom views
• Custom layouts
32
Compound drawables
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_hei...
33
ViewStub
34
ViewStub
35
ViewStub
<ViewStub
android:id="@+id/stub_import"
android:inflatedId="@+id/panel_import"
android:layout="@layout/progres...
36
Inflating a ViewStub
findViewById(R.id.stub_import).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub)
f...
37
<merge />
38
<merge />
<!-- The merge tag must be the root tag -->
<merge xmlns:android="http://schemas.android.com/apk/res/android"...
39
RelativeLayout
• Powerful
• Replace linear layouts
– A horizontal LinearLayout in a vertical one
– Or the other way aro...
40
Custom views
41
Custom views
class CustomView extends View {
public CustomView(Context context) {
super(context);
}
@Override
protected...
42
Custom layouts
43
Custom layouts
public class GridLayout extends ViewGroup {
@Override
protected void onMeasure(int widthMeasureSpec, int...
44
Agenda
• Adapters
• Backgrounds and images
• Drawing and invalidating
• Views and layouts
• Memory allocations
45
DO NOT ALLOCATE MEMORY
• As much as you can
• GC
– Stops the world
– Slow (~x00 ms)
46
Performance sensitive paths
Measurement onMeasure()
Layout onLayout()
Drawing draw()
dispatchDraw()
onDraw()
Events han...
47
Fail fast
int prevLimit = -1;
try {
// Limit the number of allocated objects
prevLimit = Debug.setAllocationLimit(0);
/...
Demo, allocation tracker
49
Manage your objects
• SoftReferences
– Excellent for memory caches
• WeakReferences
– Avoids memory leaks
50
Simple cache
private final HashMap<String, SoftReference<T>> mCache;
public put(String key, T value) {
mCache.put(key, ...
51
Resources
• http://d.android.com
• http://source.android.com
• http://android.git.kernel.org
• http://code.google.com/p...
Q&A
Th 0230 turbo_chargeyourui-howtomakeyourandroidu_ifastandefficient
Th 0230 turbo_chargeyourui-howtomakeyourandroidu_ifastandefficient
Upcoming SlideShare
Loading in...5
×

Th 0230 turbo_chargeyourui-howtomakeyourandroidu_ifastandefficient

242

Published on

Published in: Technology, Art & Photos
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
242
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
8
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Transcript of "Th 0230 turbo_chargeyourui-howtomakeyourandroidu_ifastandefficient"

  1. 1. Turbo-charge your UI Romain Guy May 29, 2009
  2. 2. Disclaimer
  3. 3. 4 Agenda • Adapters • Backgrounds and images • Drawing and invalidating • Views and layouts • Memory allocations
  4. 4. 5 Agenda • Adapters • Backgrounds and images • Drawing and invalidating • Views and layouts • Memory allocations
  5. 5. 6 Adapters • Awesome • Painful • Do you even know how ListView works?
  6. 6. 7 Man in the middle
  7. 7. 8 Gimme views • For each position – Adapter.getView() • A new View is returned – Expensive • What if I have 1,000,000 items?
  8. 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. 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. 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. 11. 12 Even better static class ViewHolder { TextView text; ImageView icon; }
  12. 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. 13. 14 Is it worth it? 0 10 20 30 40 Dumb Recycling views ViewHolder Frames per second
  14. 14. 15 Agenda • Adapters • Backgrounds and images • Drawing and invalidating • Views and layouts • Memory allocations
  15. 15. 16 Don’t be greedy • Background drawables always fit the view – Stretching may occur • Runtime scaling is expensive
  16. 16. 17 How expensive? 0 12.5 25 37.5 50 Auto-scaled Pre-scaled Frames per second
  17. 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. 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. 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. 20. Removing the background 21 <activity android:name="MyApplication" android:theme="@style/NoBackgroundTheme"> <!-- intent filters and stuff --> </activity>
  21. 21. 22 What do I get? 0 14 28 42 56 With background No background Frames per second
  22. 22. 23 Good news!
  23. 23. 24 Agenda • Adapters • Backgrounds and images • Drawing and invalidating • Views and layouts • Memory allocations
  24. 24. Redraw efficiently • invalidate() – So easy – So expensive • Dirty regions – invalidate(Rect) – invalidate(left, top, right, bottom) 25
  25. 25. Demo, invalidating Home
  26. 26. 27 Just do it 0 10 20 30 40 50 invalidate() invalidate(Rect) invalidate(int, int, int, int) Frames per second
  27. 27. 28 Agenda • Adapters • Backgrounds and images • Drawing and invalidating • Views and layouts • Memory allocations
  28. 28. 29 Fewer is better • Many views – Longer startup time – Slower measurement – Slower layout – Slower drawing • Deep hierarchies – StackOverflowException – Slow... slow... slow...
  29. 29. HierarchyViewer
  30. 30. 31 A few solutions • TextView’s compound drawables • ViewStub • <merge /> • RelativeLayout • Custom views • Custom layouts
  31. 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. 32. 33 ViewStub
  33. 33. 34 ViewStub
  34. 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. 35. 36 Inflating a ViewStub findViewById(R.id.stub_import).setVisibility(View.VISIBLE); // or View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
  36. 36. 37 <merge />
  37. 37. 38 <merge /> <!-- The merge tag must be the root tag --> <merge xmlns:android="http://schemas.android.com/apk/res/android"> <!-- Content --> </merge>
  38. 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. 39. 40 Custom views
  40. 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. 41. 42 Custom layouts
  42. 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. 43. 44 Agenda • Adapters • Backgrounds and images • Drawing and invalidating • Views and layouts • Memory allocations
  44. 44. 45 DO NOT ALLOCATE MEMORY • As much as you can • GC – Stops the world – Slow (~x00 ms)
  45. 45. 46 Performance sensitive paths Measurement onMeasure() Layout onLayout() Drawing draw() dispatchDraw() onDraw() Events handling dispatchTouchEvent() onTouchEvent() Adapters getView() bindView()
  46. 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. 47. Demo, allocation tracker
  48. 48. 49 Manage your objects • SoftReferences – Excellent for memory caches • WeakReferences – Avoids memory leaks
  49. 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. 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. 51. Q&A
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×