Performance - Optimierung mit und ohne Android Developer Tools Dominik Helleberg Köln - 25.09.2014
Performance Analysieren Verstehen Fixen 2
Performance-Probleme... Netzwerk / Cache 3
Performance-Probleme... Netzwerk / Cache 4
Performance-Probleme... Netzwerk / Cache 5
Performance-Probleme... Netzwerk / Cache 6
Performance-Probleme... User Interface 7
Performance-Probleme... User Interface 8
Performance Probleme Grrrrrr https://flic.kr/p/6mvmji grrr sookie 9
Performance messen Laufzeiten https://flic.kr/p/6old5r Tacho Thaddäus Zoltkowski 10
Performance messen Laufzeiten Log long start = System.nanoTime(); /** Do things... */ Log.d(TAG, Doing took +(System.nanoTime()-start)); 11
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 12
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 13
Performance messen Laufzeiten Traceview 14
Performance messen Laufzeiten Traceview 15
Performance messen Laufzeiten Systrace ab API Level 16 (4.1) 16
Performance messen Laufzeiten Systrace ab API Level 18 (4.3) Trace.beginSection("bind-view"); /*do things... */ Trace.endSection(); systrace - t 20 - b 10000 gfx input view sched freq - a de.inovex.samples 17
Performance messen Frames 18
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 19
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 20
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. http://www.curious-creature.org/docs/android-performance-case-study-1.html 21
Beispiel App - flickr 22
Beispiel App - Anforderung 23
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/ 34398594@N04.jpg?1378603265#34398594@N04</flickr:buddyicon> </author> <link rel="enclosure" type="image/jpeg" href="http://farm6.staticflickr.com/ 5581/14968952316_f9bb0999d2_b.jpg" />... 24
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> 25
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; 26
Beispiel App - Implementierung Adapter Image Loading Don t Async Task? even new ThumbnailTask(position, url,imageview).executeonexecutor(mexecutor, null); Picasso think about it Picasso.with(getContext()).load(flickrFeedEntry.imageURL).transform(new CropSquareTransformation()).into(imageView); Picasso.with(getContext()).load(flickrFeedEntry.authorIconURI).transform(new CropSquareTransformation()).into(authorPic); 27
Beispiel App - Demo 28
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; 29
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(); 30
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 31
Analyse 1 getview - traceview 32
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; } 33
App v2 getview - optimiert 34
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 35
App v2 Analyse - Systrace $> systrace -a de.inovex.samples gfx input view dalvik res sched 36
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 37
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 38
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* 39
App v3 Wie groß ist mein ImageView? int size = Math.max(imageView.getWidth(), imageview.getheight()); Invalidate 0,0 320,300 Measure & Layout Draw 40
App v3 Wie groß ist mein ImageView? final ViewTreeObserver viewtreeobserver = mgridview.getviewtreeobserver(); viewtreeobserver.addonpredrawlistener( "new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onpredraw() { " "if(viewtreeobserver.isalive()) " "//do things " "return true; }); } viewtreeobserver.removeonpredrawlistener(this); Invalidate Measure & Layout Draw 41
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 42
App v3 Wie groß ist mein ImageView? imageview.post(new Runnable() { @Override public void run() { }); } "//Do things Invalidate Measure & Layout Draw 43
App v3 Bilder optimiert 44
App v3 Done? DONE? Not yet... https://flic.kr/p/nqwvf Flensburger Pilsner fleno.de 45
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(); } } 46
App v3 Cache? 47
App v3 Prost https://flic.kr/p/nqwvf Flensburger Pilsner fleno.de 48
Performance Tipps + Tricks Flache Layout-Hierarchien -> Hierarchy Viewer 49
Performance Tipps + Tricks Flache Layout-Hierarchien -> Scalpel https://github.com/jakewharton/scalpel 50
Performance Tipps + Tricks Flache Layout-Hierarchien -> Droid Inspector http://www.sriramramani.com/droidinspector/ 51
Performance Tipps + Tricks Overdraw TODO: URL 52
Performance Tipps + Tricks Garbarge Collection -> zu viele Objekte? -> Allocation Tracker 53
Immer 60 FPS 54
Danke