performance-optimierung mit und ohne android developer tools · performance - optimierung mit und...
TRANSCRIPT
Performance - Optimierung
mit und ohne Android Developer Tools
Dominik Helleberg
Köln - 25.09.2014
2
Performance
Analysieren
Verstehen
Fixen
3
Performance-Probleme... Netzwerk / Cache
4
Performance-Probleme... Netzwerk / Cache
5
Performance-Probleme... Netzwerk / Cache
6
Performance-Probleme... Netzwerk / Cache
7
Performance-Probleme... User Interface
8
Performance-Probleme... User Interface
https://flic.kr/p/6MVMJi grrr | sookie
9
Performance Probleme Grrrrrr
https://flic.kr/p/6oLD5r Tacho | Thaddäus Zoltkowski
10
Performance messen Laufzeiten
11
Performance messen Laufzeiten
Log !long start = System.nanoTime(); !!/** Do things.... */ !!Log.d(TAG, “Doing took” +(System.nanoTime()-start)); !
12
Performance messen Laufzeiten
Timing Logger !
TimingLogger timings = new TimingLogger(TAG, "mURL"); !/** Do cache */ !timings.addSplit(“cache"); !/** Do load */ !timings.addSplit(“load"); !/** and scale! */ !timings.addSplit(“scale"); !timings.dumpToLog(); !
$> adb shell setprop log.tag.TTTask VERBOSE !
TTTask D mURL: begin ! D mURL: 4 ms, cache ! D mURL: 1819 ms, load ! D mURL: 8 ms, scale ! D mURL: end, 1831 ms !
13
Performance messen Laufzeiten
Hugo !apply plugin: 'hugo‘ !!classpath 'com.jakewharton.hugo:hugo-plugin:1.1.+‘ !!!
import hugo.weaving.DebugLog; !!@DebugLog !protected Bitmap doInBackground(Void... arg0) { !!} !
" " " D ⇢ doInBackground(arg0=null) !!Activity$ThumbnailTask D ⇠ doInBackground [1015ms] = !
" " "android.graphics.Bitmap@b187ec38 !
14
Performance messen Laufzeiten
Traceview!
15
Performance messen Laufzeiten
Traceview!
16
Performance messen Laufzeiten
Systrace ab API Level 16 (4.1) !
17
Performance messen Laufzeiten
Systrace ab API Level 18 (4.3) !
systrace -‐t 20 -‐b 10000 gfx input view sched freq -‐a de.inovex.samples
Trace.beginSection("bind-view"); !!/*do things ... */ !!!Trace.endSection(); !!!
18
Performance messen Frames
http://www.curious-creature.org/docs/android-performance-case-study-1.html 19
Performance messen Frames
(Blau) Draw is the time spent building display lists in Java. It indicates how much time is spent running methods such as View.onDraw(Canvas).
http://www.curious-creature.org/docs/android-performance-case-study-1.html 20
Performance messen Frames
(ROT) Process is the time spent by Android’s 2D renderer to execute the display lists. The more Views in your hierarchy, the more drawing commands must be executed.
http://www.curious-creature.org/docs/android-performance-case-study-1.html 21
Performance messen Frames
(Orange) Execute is the time it took to send a frame to the compositor. This part of the graph is usually small.
22
Beispiel App - flickr
23
Beispiel App - Anforderung
24
Beispiel App - Implementierung
• flickr API http://ycpi.api.flickr.com/services/feeds/photos_public.gne?tags=berlin
<entry> ! <title>Balkonien, Berlin, 2014.</title> ! <link rel="alternate" type="text/html" href="http://www.flickr.com/photos/schommsen/14968952316/"/> ! <id>tag:flickr.com,2005:/photo/14968952316</id> ! <published>2014-08-21T18:36:13Z</published> ! <updated>2014-08-21T18:36:13Z</updated> ! <author> ! <name>schommsen</name> ! <uri>http://www.flickr.com/people/schommsen/</uri> ! <flickr:buddyicon>http://farm4.staticflickr.com/3759/buddyicons/ [email protected]?1378603265#34398594@N04</flickr:buddyicon> ! </author> ! <link rel="enclosure" type="image/jpeg" href="http://farm6.staticflickr.com/5581/14968952316_f9bb0999d2_b.jpg" /> !.... !!!!
25
Beispiel App - Implementierung View-Item
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" ! android:layout_width="match_parent“ android:layout_height="match_parent“> ! <ImageView! android:id="@+id/fli_picture_imageview" ! android:layout_width="280dp" ! android:layout_height="280dp" ! android:layout_centerVertical="true" ! android:layout_centerHorizontal="true" /> ! <ImageView! android:layout_width="40dp" ! android:layout_height="40dp" ! android:id="@+id/fli_authorPic_imageview" ! android:layout_alignParentBottom="true" ! android:layout_alignParentLeft="true" /> ! <TextView ! android:id="@+id/fli_title_textview" ! android:layout_alignParentTop="true" ! android:layout_alignParentLeft="true" /> ! <TextView ! android:textAppearance="?android:attr/textAppearanceSmall“ ! android:id="@+id/fli_date_textview" ! android:layout_alignParentRight="true" ! android:layout_alignParentBottom="true" /> !!</RelativeLayout> !
26
Beispiel App - Implementierung Adapter
@Override !public View getView(int position, View convertView, ViewGroup parent) { !! View view = mInflater.inflate(R.layout.flickr_item_list_entry, parent, false); ! ! ImageView imageView = (ImageView) view.findViewById(R.id.fli_picture_imageview); ! ImageView authorPic = (ImageView) view.findViewById(R.id.fli_authorPic_imageview); ! TextView dateTaken = (TextView) view.findViewById(R.id.fli_date_textview); ! TextView title = (TextView) view.findViewById(R.id.fli_title_textview); !! title.setText(flickrFeedEntry.title); !! Date nowDate = new Date(); ! nowDate.setTime(nowDate.getTime() - flickrFeedEntry.dateTaken.getTime()); ! SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd"); ! dateTaken.setText(simpleDateFormat.format(nowDate) + " Days ago"); !! // ToDo: Image Loading ! return view; !} !!!
27
Beispiel App - Implementierung Adapter – Image Loading
!new ThumbnailTask(position, url,imageView).executeOnExecutor(mExecutor, null); !!!!
• Async Task? Don‘t even think about it!
• Picasso Picasso.with(getContext()).load(flickrFeedEntry.imageURL).transform(new CropSquareTransformation()).into(imageView); !!Picasso.with(getContext()).load(flickrFeedEntry.authorIconURI).transform(new CropSquareTransformation()).into(authorPic); !!
28
Beispiel App - Demo
29
Beispiel App - Implementierung Adapter
public View getView(int position, View convertView, ViewGroup parent) { !! View view = mInflater.inflate(R.layout.flickr_item_list_entry, parent, false); ! ! ImageView imageView = (ImageView) view.findViewById(R.id.fli_picture_imageview); ! ImageView authorPic = (ImageView) view.findViewById(R.id.fli_authorPic_imageview); ! TextView dateTaken = (TextView) view.findViewById(R.id.fli_date_textview); ! TextView title = (TextView) view.findViewById(R.id.fli_title_textview); !! // Image loading here !! title.setText(flickrFeedEntry.title); !! Date nowDate = new Date(); ! nowDate.setTime(nowDate.getTime() - flickrFeedEntry.dateTaken.getTime()); ! SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd"); ! dateTaken.setText(simpleDateFormat.format(nowDate) + " Days ago"); !! return view; !} !!!
30
Analyse – 1 getView
TimingLogger timings = new TimingLogger(TAG, “getView"); !!view = mInflater.inflate(R.layout.flickr_item_list_entry, parent, false); !//... !!timings.addSplit(“find/inflate"); !!//Picasso.with... !!timings.addSplit(“picasso"); !!//textView.setText(...) !!timings.addSplit(“filldata"); !timings.dumpToLog(); !
31
Analyse – 1 getView
D getView: begin !D getView: 4 ms, find/inflate !D getView: 1 ms, picasso !D getView: 1 ms, filldata!D getView: end, 6 ms !!D getView: begin !D getView: 2 ms, find/inflate !D getView: 0 ms, picasso !D getView: 2 ms, filldata!D getView: end, 4 ms !!D getView: begin !D getView: 5 ms, find/inflate !D getView: 1 ms, picasso !D getView: 0 ms, filldata!D getView: end, 6 ms !!
32
Analyse – 1 getView - traceview
33
Analyse – 1 getView - optimiert
public View getView(int position, View convertView, ViewGroup parent) { ! View view = convertView; ! if(view == null) { ! view = mInflater.inflate(R.layout.flickr_item_list_entry, parent, false); ! ViewHolder viewHolder = new ViewHolder(); !! viewHolder.imageView = (ImageView)view.findViewById(R.id.fli_picture_imageview); ! //... ! view.setTag(viewHolder); ! } ! ViewHolder viewHolder = (ViewHolder) view.getTag(); !! //picasso loading... !! viewHolder.title.setText(flickrFeedEntry.title); ! mNowDate.setTime(System.currentTimeMillis() - "
"flickrFeedEntry.dateTaken.getTime()); ! viewHolder.dateTaken.setText(mSimpleDateFormat.format(mNowDate) + DAYS); !! return view; !} !!!
34
App v2 getView - optimiert
35
App v2 getView - optimiert
D getView: 6 ms, find/inflate ! D getView: 0 ms, picasso ! D getView: 1 ms, filldata! D getView: end, 7 ms !! D getView: begin ! D getView: 0 ms, find/inflate ! D getView: 0 ms, picasso ! D getView: 0 ms, filldata! D getView: end, 0 ms !! D getView: begin ! D getView: 0 ms, find/inflate ! D getView: 0 ms, picasso ! D getView: 1 ms, filldata! D getView: end, 1 ms !!
36
App v2 Analyse - Systrace
$> systrace -a de.inovex.samples gfx input view dalvik res sched !
37
App v2 Analyse - Logcat
dalvikvm D GC_FOR_ALLOC freed 5077K, 30% free 19358K/27632K, paused 20ms, total 20ms !! D GC_FOR_ALLOC freed 71K, 19% free 22504K/27632K, paused 16ms, total 16ms !!dalvikvm-heap I Grow heap (frag case) to 25.011MB for 3145744-byte allocation !! dalvikvm D GC_FOR_ALLOC freed 0K, 17% free 25576K/30708K, paused 21ms, total 21ms!
38
App v2 Analyse – Bild-Größen
<link rel="enclosure" type="image/jpeg" href="http://farm6.staticflickr.com/5581/14968952316_f9bb0999d2_b.jpg" /> !!$> curl http://farm6.staticflickr.com/5581/14968952316_f9bb0999d2_b.jpg > out.jpg !!$> identify out.jpg !out.jpg JPEG 600x900 600x900+0+0 8-bit sRGB 183KB 0.000u 0:00.000!
Speicher: 600 x 900 x 4 = 2.2 Megabytes 4 Zeilen à 2 Bilder: ~ 18 MBytes
$> getprop dalvik.vm.heapgrowthlimit!64m !
39
App v2 Analyse – Bild-Größen – Flickr - Doku
https://www.flickr.com/services/api/misc.urls.html!s "small square 75x75 !q "large square 150x150 !t "thumbnail, 100 on longest side !m "small, 240 on longest side !n "small, 320 on longest side !- "medium, 500 on longest side !z "medium 640, 640 on longest side !c "medium 800, 800 on longest side† !b "large, 1024 on longest side* !
40
App v3 Wie groß ist mein ImageView?
int size = Math.max(imageView.getWidth(), imageView.getHeight()); !!
Invalidate Measure & Layout Draw
0,0 320,300
41
App v3 Wie groß ist mein ImageView?
final ViewTreeObserver viewTreeObserver = mGridView.getViewTreeObserver(); !viewTreeObserver.addOnPreDrawListener( !
"new ViewTreeObserver.OnPreDrawListener() { ! @Override ! public boolean onPreDraw() { !
" "if(viewTreeObserver.isAlive()) ! viewTreeObserver.removeOnPreDrawListener(this); !
" "//do things !" "return true; !
} ! }); !
Invalidate Measure & Layout Draw
42
App v3 Wie groß ist mein ImageView?
public class MyImageView extends ImageView { !! @Override! protected void onSizeChanged(int w, int h, int oldw, int oldh) { ! super.onSizeChanged(w, h, oldw, oldh); !
"//use w and h ! } !!!
Invalidate Measure & Layout Draw
43
App v3 Wie groß ist mein ImageView?
!imageView.post(new Runnable() { ! @Override ! public void run() { !
"//Do things ! } !}); !!
Invalidate Measure & Layout Draw
44
App v3 Bilder optimiert
45
App v3 Done?
https://flic.kr/p/nqwvF Flensburger Pilsner | fleno.de
DONE?
Not yet...
46
App v3 Response Cache (API Level 13)
protected void onCreate(Bundle savedInstanceState) { !... ! try { ! File httpCacheDir = new File(context.getCacheDir(), "http"); ! long httpCacheSize = 10 * 1024 * 1024; // 10 MiB ! HttpResponseCache.install(httpCacheDir, httpCacheSize); ! } ! catch (IOException ex) { ! Log.i(TAG, "HTTP response cache installation failed:" + ex); ! } !}!protected void onStop() { ! super.onStop(); ! HttpResponseCache cache = HttpResponseCache.getInstalled(); ! if (cache != null) { ! cache.flush(); ! } !} !!
47
App v3 Cache?
48
App v3 Prost!
https://flic.kr/p/nqwvF Flensburger Pilsner | fleno.de
49
Performance Tipps + Tricks Flache Layout-Hierarchien -> Hierarchy Viewer
https://github.com/JakeWharton/scalpel 50
Performance Tipps + Tricks Flache Layout-Hierarchien -> Scalpel
http://www.sriramramani.com/droidinspector/ 51
Performance Tipps + Tricks Flache Layout-Hierarchien -> Droid Inspector
TODO: URL 52
Performance Tipps + Tricks Overdraw
53
Performance Tipps + Tricks Garbarge Collection -> zu viele Objekte? -> Allocation Tracker
54
Immer 60 FPS
Danke!