SlideShare a Scribd company logo
Performance Tools
Andrei Diaconu
Andrei Diaconu
Andrei Diaconu
Andrei Diaconu
Andrei Diaconu
• Cofounder of Android Iași
Andrei Diaconu
• Cofounder of Android Iași
• 5 years of Android
Andrei Diaconu
• Cofounder of Android Iași
• 5 years of Android
• Trainer & Speaker
Why is my app dropping below 60fps?
Why is my app dropping below 60fps?
Why is my app draining the battery?
Why is my app dropping below 60fps?
Why is my app dropping below 60fps?
Why is my app dropping below 60fps?
• Simple list
Why is my app dropping below 60fps?
• Simple list
• Items have some text
Why is my app dropping below 60fps?
• Simple list
• Items have some text
Why is my app dropping below 60fps?
• Simple list
• Items have some text
• Scroll is not smooth
• Scroll is not smooth
• Scroll is not smooth
Why?
• Scroll is not smooth
Why?
Can we make sure?
• Scroll is not smooth
Why?
Can we make sure?
Can we make sure?
Can we make sure?
Can we make sure?
Can we make sure?
Frames
Frames
Time
Frames
16ms line
Time
Frames
16ms line
Time
Choreographer: Skipped 34 frames! The application
may be doing too much work on its main thread.
Traceview
Traceview
• Measure how long each method takes to execute
Traceview
• Measure how long each method takes to execute
• Analyse measurements using Traceview
Traceview
• Measure how long each method takes to execute
Traceview
//Start in OnResume

Debug.startMethodTracing("bad_list");
• Measure how long each method takes to execute
Traceview
//Start in OnResume

Debug.startMethodTracing("bad_list");
//Stop in OnPause

Debug.stopMethodTracing();
• Measure how long each method takes to execute
Traceview
//Start in OnResume

Debug.startMethodTracing("bad_list");
//Stop in OnPause

Debug.stopMethodTracing();
//Grab using adb

adb pull
• Measure how long each method takes to execute
Traceview
//Start in OnResume

Debug.startMethodTracing("bad_list");
//Stop in OnPause

Debug.stopMethodTracing();
//Grab using adb

adb pull
• Measure how long each method takes to execute
//Grab using adb

adb pull /sdcard/bad_list.trace bad_list.trace
Traceview
//Start in OnResume

Debug.startMethodTracing("bad_list");
//Stop in OnPause

Debug.stopMethodTracing();
//Grab using adb

adb pull
• Measure how long each method takes to execute
//Needs permission
WRITE_EXTERNAL_STORAGE
//Grab using adb

adb pull /sdcard/bad_list.trace bad_list.trace
Traceview
//Start in OnResume

Debug.startMethodTracing("bad_list");
//Stop in OnPause

Debug.stopMethodTracing();
//Grab using adb

adb pull
• Measure how long each method takes to execute
//Needs permission
WRITE_EXTERNAL_STORAGE
//Grab using adb

adb pull /sdcard/bad_list.trace bad_list.trace
Traceview
• Measure how long each method takes to execute
Traceview
• Measure how long each method takes to execute
Traceview
• Measure how long each method takes to execute
• Analyse measurements using Traceview• Analyse measurements using Traceview
Traceview
• Measure how long each method takes to execute
• Analyse measurements using Traceview
• Analyse measurements using Traceview
Traceview
• Measure how long each method takes to execute
• Analyse measurements using Traceview
• Analyse measurements using Traceview
Traceview
• Measure how long each method takes to execute
• Analyse measurements using Traceview
• Analyse measurements using Traceview
~ 2 seconds
~ 200 ms
Adaptor -> getView()
~ 200 ms
inflate()
inflate() 4 x Html.fromHtml()
@Override

public View getView(int position, View convertView, ViewGroup parent) {


View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_jumpy_list, parent, false);



TextView text1 = (TextView) view.findViewById(R.id.item_text1);

TextView text2 = (TextView) view.findViewById(R.id.item_text2);

TextView text3 = (TextView) view.findViewById(R.id.item_text3);

TextView text4 = (TextView) view.findViewById(R.id.item_text4);



String string1 = parent.getContext().getString(R.string.item_number_x, position);

String string2 = parent.getContext().getString(R.string.item_description);

String string3 = parent.getContext().getString(R.string.item_details);

String string4 = parent.getContext().getString(R.string.item_related);



text1.setText(Html.fromHtml(string1));

text2.setText(Html.fromHtml(string2));

text3.setText(Html.fromHtml(string3));

text4.setText(Html.fromHtml(string4));


return view;

}
@Override

public View getView(int position, View convertView, ViewGroup parent) {


View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_jumpy_list, parent, false);



TextView text1 = (TextView) view.findViewById(R.id.item_text1);

TextView text2 = (TextView) view.findViewById(R.id.item_text2);

TextView text3 = (TextView) view.findViewById(R.id.item_text3);

TextView text4 = (TextView) view.findViewById(R.id.item_text4);



String string1 = parent.getContext().getString(R.string.item_number_x, position);

String string2 = parent.getContext().getString(R.string.item_description);

String string3 = parent.getContext().getString(R.string.item_details);

String string4 = parent.getContext().getString(R.string.item_related);



text1.setText(Html.fromHtml(string1));

text2.setText(Html.fromHtml(string2));

text3.setText(Html.fromHtml(string3));

text4.setText(Html.fromHtml(string4));


return view;

}
@Override

public View getView(int position, View convertView, ViewGroup parent) {


View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_jumpy_list, parent, false);



TextView text1 = (TextView) view.findViewById(R.id.item_text1);

TextView text2 = (TextView) view.findViewById(R.id.item_text2);

TextView text3 = (TextView) view.findViewById(R.id.item_text3);

TextView text4 = (TextView) view.findViewById(R.id.item_text4);



String string1 = parent.getContext().getString(R.string.item_number_x, position);

String string2 = parent.getContext().getString(R.string.item_description);

String string3 = parent.getContext().getString(R.string.item_details);

String string4 = parent.getContext().getString(R.string.item_related);



text1.setText(Html.fromHtml(string1));

text2.setText(Html.fromHtml(string2));

text3.setText(Html.fromHtml(string3));

text4.setText(Html.fromHtml(string4));


return view;

}
@Override

public View getView(int position, View convertView, ViewGroup parent) {


View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_jumpy_list, parent, false);



TextView text1 = (TextView) view.findViewById(R.id.item_text1);

TextView text2 = (TextView) view.findViewById(R.id.item_text2);

TextView text3 = (TextView) view.findViewById(R.id.item_text3);

TextView text4 = (TextView) view.findViewById(R.id.item_text4);



String string1 = parent.getContext().getString(R.string.item_number_x, position);

String string2 = parent.getContext().getString(R.string.item_description);

String string3 = parent.getContext().getString(R.string.item_details);

String string4 = parent.getContext().getString(R.string.item_related);



text1.setText(Html.fromHtml(string1));

text2.setText(Html.fromHtml(string2));

text3.setText(Html.fromHtml(string3));

text4.setText(Html.fromHtml(string4));


return view;

}
@Override

public View getView(int position, View convertView, ViewGroup parent) {


No recycling



No View Holder





Html.fromHtml is slow


return view;

}
But 200ms?
Isn't this a bit much?
But 200ms?
Isn't this a bit much?
Method tracking has a big impact itself
Systrace
measure at kernel level
Systrace
Systrace
Systrace
Systrace
Systrace
It will run for 5 seconds
Hit Ok and scroll the list
Alert: Inflation during ListView recycling
Time spent: 103.545 ms
ListView items inflated: 20
@Override

public View getView(int position, View convertView, ViewGroup parent) {



View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_jumpy_list, parent, false);







TextView text1 = (TextView) view.findViewById(R.id.item_text1);

TextView text2 = (TextView) view.findViewById(R.id.item_text2);

TextView text3 = (TextView) view.findViewById(R.id.item_text3);

TextView text4 = (TextView) view.findViewById(R.id.item_text4);





String string1 = parent.getContext().getString(R.string.item_number_x, position);

String string2 = parent.getContext().getString(R.string.item_description);

String string3 = parent.getContext().getString(R.string.item_details);

String string4 = parent.getContext().getString(R.string.item_related);





text1.setText(Html.fromHtml(string1));

text2.setText(Html.fromHtml(string2));

text3.setText(Html.fromHtml(string3));

text4.setText(Html.fromHtml(string4));





return view;

}
@Override

public View getView(int position, View convertView, ViewGroup parent) {

Trace.beginSection("inflating");

View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_jumpy_list, parent, false);

Trace.endSection();



Trace.beginSection("noViewHolder");

TextView text1 = (TextView) view.findViewById(R.id.item_text1);

TextView text2 = (TextView) view.findViewById(R.id.item_text2);

TextView text3 = (TextView) view.findViewById(R.id.item_text3);

TextView text4 = (TextView) view.findViewById(R.id.item_text4);

Trace.endSection();



String string1 = parent.getContext().getString(R.string.item_number_x, position);

String string2 = parent.getContext().getString(R.string.item_description);

String string3 = parent.getContext().getString(R.string.item_details);

String string4 = parent.getContext().getString(R.string.item_related);



Trace.beginSection("fromHtml");

text1.setText(Html.fromHtml(string1));

text2.setText(Html.fromHtml(string2));

text3.setText(Html.fromHtml(string3));

text4.setText(Html.fromHtml(string4));

Trace.endSection();



return view;

}
inflating
inflating noViewHolder
inflating noViewHolder
fromHtml
• obtainView = ~5ms
• obtainView = ~5ms
• doFrame = ~20 * obtainView
• obtainView = ~5ms
• doFrame = ~20 * obtainView
• each frame = ~100ms
• obtainView = ~5ms
• doFrame = ~20 * obtainView
• each frame = ~100ms
Alert: Inflation during ListView recycling
Time spent: 103.545 ms
ListView items inflated: 20
Why is my app dropping below 60fps?
Why is my app dropping below 60fps?
Why is my app draining the battery?
Why is my app draining the battery?
Why is my app draining the battery?
What is a wake lock?
Why is my app draining the battery?
Why is my app draining the battery?
Battery Historian 2.0
Why is my app draining the battery?
Battery Historian 2.0
Why is my app draining the battery?
Battery Historian 2.0
adb bugreport > bugreport.txt
Why is my app draining the battery?
Battery Historian 2.0
adb bugreport > bugreport.txt
go run battery-historian.go
Why is my app draining the battery?
Battery Historian 2.0
adb bugreport > bugreport.txt
go run battery-historian.go
open http://127.0.0.1:9999
public static class UselessWorker {

Runnable uselessWorker = new Runnable() {

@Override

public void run() {

PowerManager pm = (PowerManager) BadApplication.instance

.getSystemService(Context.POWER_SERVICE);

PowerManager.WakeLock wakeLock = 

pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "cool wakelock tag");

wakeLock.acquire();



//Some useless, but hard work



wakeLock.release();

try {

Thread.sleep(45 * 1000);

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

work();

}

}

};



private void work() {

new Thread(uselessWorker, "cool thread name").start();

}

}
public static class UselessWorker {

Runnable uselessWorker = new Runnable() {

@Override

public void run() {

PowerManager pm = (PowerManager) BadApplication.instance

.getSystemService(Context.POWER_SERVICE);

PowerManager.WakeLock wakeLock = 

pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "cool wakelock tag");

wakeLock.acquire();



//Some useless, but hard work



wakeLock.release();

try {

Thread.sleep(45 * 1000);

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

work();

}

}

};



private void work() {

new Thread(uselessWorker, "cool thread name").start();

}

}
public static class UselessWorker {

Runnable uselessWorker = new Runnable() {

@Override

public void run() {

PowerManager pm = (PowerManager) BadApplication.instance

.getSystemService(Context.POWER_SERVICE);

PowerManager.WakeLock wakeLock = 

pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "cool wakelock tag");

wakeLock.acquire();



//Some useless, but hard work



wakeLock.release();

try {

Thread.sleep(45 * 1000);

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

work();

}

}

};



private void work() {

new Thread(uselessWorker, "cool thread name").start();

}

}
public static class UselessWorker {

Runnable uselessWorker = new Runnable() {

@Override

public void run() {

PowerManager pm = (PowerManager) BadApplication.instance

.getSystemService(Context.POWER_SERVICE);

PowerManager.WakeLock wakeLock = 

pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "cool wakelock tag");

wakeLock.acquire();



//Some useless, but hard work



wakeLock.release();

try {

Thread.sleep(45 * 1000);

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

work();

}

}

};



private void work() {

new Thread(uselessWorker, "cool thread name").start();

}

}
public static class UselessWorker {

Runnable uselessWorker = new Runnable() {

@Override

public void run() {

PowerManager pm = (PowerManager) BadApplication.instance

.getSystemService(Context.POWER_SERVICE);

PowerManager.WakeLock wakeLock = 

pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "cool wakelock tag");

wakeLock.acquire();



//Some useless, but hard work



wakeLock.release();

try {

Thread.sleep(45 * 1000);

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

work();

}

}

};



private void work() {

new Thread(uselessWorker, "cool thread name").start();

}

}
public static class UselessWorker {

Runnable uselessWorker = new Runnable() {

@Override

public void run() {

PowerManager pm = (PowerManager) BadApplication.instance

.getSystemService(Context.POWER_SERVICE);

PowerManager.WakeLock wakeLock = 

pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "cool wakelock tag");

wakeLock.acquire();



//Some useless, but hard work



wakeLock.release();

try {

Thread.sleep(45 * 1000);

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

work();

}

}

};



private void work() {

new Thread(uselessWorker, "cool thread name").start();

}

}
public static class UselessWorker {

Runnable uselessWorker = new Runnable() {

@Override

public void run() {

PowerManager pm = (PowerManager) BadApplication.instance

.getSystemService(Context.POWER_SERVICE);

PowerManager.WakeLock wakeLock = 

pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "cool wakelock tag");

wakeLock.acquire();



//Some useless, but hard work



wakeLock.release();

try {

Thread.sleep(45 * 1000);

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

work();

}

}

};



private void work() {

new Thread(uselessWorker, "cool thread name").start();

}

}
public static class UselessWorker {

Runnable uselessWorker = new Runnable() {

@Override

public void run() {

PowerManager pm = (PowerManager) BadApplication.instance

.getSystemService(Context.POWER_SERVICE);

PowerManager.WakeLock wakeLock = 

pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "cool wakelock tag");

wakeLock.acquire();



//Some useless, but hard work



wakeLock.release();

try {

Thread.sleep(45 * 1000);

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

work();

}

}

};



private void work() {

new Thread(uselessWorker, "cool thread name").start();

}

}
?
?
Questions
http://j.mp/fps60
http://j.mp/androidiasi

More Related Content

Similar to Performance tools Droidcon Eastern Europe

Kicking off with Zend Expressive and Doctrine ORM (ZendCon 2016)
Kicking off with Zend Expressive and Doctrine ORM (ZendCon 2016)Kicking off with Zend Expressive and Doctrine ORM (ZendCon 2016)
Kicking off with Zend Expressive and Doctrine ORM (ZendCon 2016)
James Titcumb
 
Kicking off with Zend Expressive and Doctrine ORM (PHPNW2016)
Kicking off with Zend Expressive and Doctrine ORM (PHPNW2016)Kicking off with Zend Expressive and Doctrine ORM (PHPNW2016)
Kicking off with Zend Expressive and Doctrine ORM (PHPNW2016)
James Titcumb
 
Schema design short
Schema design shortSchema design short
Schema design shortMongoDB
 
Cool bonsai cool - an introduction to ElasticSearch
Cool bonsai cool - an introduction to ElasticSearchCool bonsai cool - an introduction to ElasticSearch
Cool bonsai cool - an introduction to ElasticSearch
clintongormley
 
Php Code Audits (PHP UK 2010)
Php Code Audits (PHP UK 2010)Php Code Audits (PHP UK 2010)
Php Code Audits (PHP UK 2010)Damien Seguy
 
Solr's Search Relevancy (Understand Solr's query debug)
Solr's Search Relevancy (Understand Solr's query debug)Solr's Search Relevancy (Understand Solr's query debug)
Solr's Search Relevancy (Understand Solr's query debug)
Wongnai
 
Sinatra and JSONQuery Web Service
Sinatra and JSONQuery Web ServiceSinatra and JSONQuery Web Service
Sinatra and JSONQuery Web Service
vvatikiotis
 
Rspec and Capybara Intro Tutorial at RailsConf 2013
Rspec and Capybara Intro Tutorial at RailsConf 2013Rspec and Capybara Intro Tutorial at RailsConf 2013
Rspec and Capybara Intro Tutorial at RailsConf 2013
Brian Sam-Bodden
 
Sphinx on Rails
Sphinx on RailsSphinx on Rails
Sphinx on Rails
freelancing_god
 
Introduction to R Short course Fall 2016
Introduction to R Short course Fall 2016Introduction to R Short course Fall 2016
Introduction to R Short course Fall 2016
Spencer Fox
 
Django O/R Mapper
Django O/R MapperDjango O/R Mapper
Django O/R Mapper
Ian Lewis
 
DEVIEW2013: Automating Performance Tests for Android Applications
DEVIEW2013: Automating Performance Tests for Android ApplicationsDEVIEW2013: Automating Performance Tests for Android Applications
DEVIEW2013: Automating Performance Tests for Android ApplicationsKyungmin Lee
 
Solving the Riddle of Search: Using Sphinx with Rails
Solving the Riddle of Search: Using Sphinx with RailsSolving the Riddle of Search: Using Sphinx with Rails
Solving the Riddle of Search: Using Sphinx with Rails
freelancing_god
 
Free The Enterprise With Ruby & Master Your Own Domain
Free The Enterprise With Ruby & Master Your Own DomainFree The Enterprise With Ruby & Master Your Own Domain
Free The Enterprise With Ruby & Master Your Own Domain
Ken Collins
 
Effective codereview | Dave Liddament | CODEiD
Effective codereview | Dave Liddament | CODEiDEffective codereview | Dave Liddament | CODEiD
Effective codereview | Dave Liddament | CODEiD
CODEiD PHP Community
 
How to not blow up spaceships
How to not blow up spaceshipsHow to not blow up spaceships
How to not blow up spaceships
Sabin Marcu
 
Write code that writes code!
Write code that writes code!Write code that writes code!
Write code that writes code!
Jason Feinstein
 
Write code that writes code! A beginner's guide to Annotation Processing - Ja...
Write code that writes code! A beginner's guide to Annotation Processing - Ja...Write code that writes code! A beginner's guide to Annotation Processing - Ja...
Write code that writes code! A beginner's guide to Annotation Processing - Ja...
DroidConTLV
 
Android Automated Testing
Android Automated TestingAndroid Automated Testing
Android Automated Testing
roisagiv
 
Easy R
Easy REasy R
Easy R
Ajay Ohri
 

Similar to Performance tools Droidcon Eastern Europe (20)

Kicking off with Zend Expressive and Doctrine ORM (ZendCon 2016)
Kicking off with Zend Expressive and Doctrine ORM (ZendCon 2016)Kicking off with Zend Expressive and Doctrine ORM (ZendCon 2016)
Kicking off with Zend Expressive and Doctrine ORM (ZendCon 2016)
 
Kicking off with Zend Expressive and Doctrine ORM (PHPNW2016)
Kicking off with Zend Expressive and Doctrine ORM (PHPNW2016)Kicking off with Zend Expressive and Doctrine ORM (PHPNW2016)
Kicking off with Zend Expressive and Doctrine ORM (PHPNW2016)
 
Schema design short
Schema design shortSchema design short
Schema design short
 
Cool bonsai cool - an introduction to ElasticSearch
Cool bonsai cool - an introduction to ElasticSearchCool bonsai cool - an introduction to ElasticSearch
Cool bonsai cool - an introduction to ElasticSearch
 
Php Code Audits (PHP UK 2010)
Php Code Audits (PHP UK 2010)Php Code Audits (PHP UK 2010)
Php Code Audits (PHP UK 2010)
 
Solr's Search Relevancy (Understand Solr's query debug)
Solr's Search Relevancy (Understand Solr's query debug)Solr's Search Relevancy (Understand Solr's query debug)
Solr's Search Relevancy (Understand Solr's query debug)
 
Sinatra and JSONQuery Web Service
Sinatra and JSONQuery Web ServiceSinatra and JSONQuery Web Service
Sinatra and JSONQuery Web Service
 
Rspec and Capybara Intro Tutorial at RailsConf 2013
Rspec and Capybara Intro Tutorial at RailsConf 2013Rspec and Capybara Intro Tutorial at RailsConf 2013
Rspec and Capybara Intro Tutorial at RailsConf 2013
 
Sphinx on Rails
Sphinx on RailsSphinx on Rails
Sphinx on Rails
 
Introduction to R Short course Fall 2016
Introduction to R Short course Fall 2016Introduction to R Short course Fall 2016
Introduction to R Short course Fall 2016
 
Django O/R Mapper
Django O/R MapperDjango O/R Mapper
Django O/R Mapper
 
DEVIEW2013: Automating Performance Tests for Android Applications
DEVIEW2013: Automating Performance Tests for Android ApplicationsDEVIEW2013: Automating Performance Tests for Android Applications
DEVIEW2013: Automating Performance Tests for Android Applications
 
Solving the Riddle of Search: Using Sphinx with Rails
Solving the Riddle of Search: Using Sphinx with RailsSolving the Riddle of Search: Using Sphinx with Rails
Solving the Riddle of Search: Using Sphinx with Rails
 
Free The Enterprise With Ruby & Master Your Own Domain
Free The Enterprise With Ruby & Master Your Own DomainFree The Enterprise With Ruby & Master Your Own Domain
Free The Enterprise With Ruby & Master Your Own Domain
 
Effective codereview | Dave Liddament | CODEiD
Effective codereview | Dave Liddament | CODEiDEffective codereview | Dave Liddament | CODEiD
Effective codereview | Dave Liddament | CODEiD
 
How to not blow up spaceships
How to not blow up spaceshipsHow to not blow up spaceships
How to not blow up spaceships
 
Write code that writes code!
Write code that writes code!Write code that writes code!
Write code that writes code!
 
Write code that writes code! A beginner's guide to Annotation Processing - Ja...
Write code that writes code! A beginner's guide to Annotation Processing - Ja...Write code that writes code! A beginner's guide to Annotation Processing - Ja...
Write code that writes code! A beginner's guide to Annotation Processing - Ja...
 
Android Automated Testing
Android Automated TestingAndroid Automated Testing
Android Automated Testing
 
Easy R
Easy REasy R
Easy R
 

More from Diaconu Andrei-Tudor

ListView vs RecyclerView
ListView vs RecyclerViewListView vs RecyclerView
ListView vs RecyclerView
Diaconu Andrei-Tudor
 
Mobile testing in the cloud
Mobile testing in the cloudMobile testing in the cloud
Mobile testing in the cloud
Diaconu Andrei-Tudor
 
Prezentarea ta mai buna
Prezentarea ta mai bunaPrezentarea ta mai buna
Prezentarea ta mai buna
Diaconu Andrei-Tudor
 
FiiPractic 2015 - Adroid Pro - Day 7 - Follow-up Day
FiiPractic 2015 - Adroid Pro - Day 7 - Follow-up DayFiiPractic 2015 - Adroid Pro - Day 7 - Follow-up Day
FiiPractic 2015 - Adroid Pro - Day 7 - Follow-up Day
Diaconu Andrei-Tudor
 
FiiPractic 2015 - Adroid Pro - Day 5 - SQL Day
FiiPractic 2015 - Adroid Pro - Day 5 - SQL DayFiiPractic 2015 - Adroid Pro - Day 5 - SQL Day
FiiPractic 2015 - Adroid Pro - Day 5 - SQL Day
Diaconu Andrei-Tudor
 
FiiPractic 2015 - Adroid Pro - Day 3 - API Day
FiiPractic 2015 - Adroid Pro - Day 3 - API DayFiiPractic 2015 - Adroid Pro - Day 3 - API Day
FiiPractic 2015 - Adroid Pro - Day 3 - API Day
Diaconu Andrei-Tudor
 
FiiPractic 2015 - Adroid Pro - Day 1 - UI Day
FiiPractic 2015 - Adroid Pro - Day 1 - UI DayFiiPractic 2015 - Adroid Pro - Day 1 - UI Day
FiiPractic 2015 - Adroid Pro - Day 1 - UI Day
Diaconu Andrei-Tudor
 

More from Diaconu Andrei-Tudor (7)

ListView vs RecyclerView
ListView vs RecyclerViewListView vs RecyclerView
ListView vs RecyclerView
 
Mobile testing in the cloud
Mobile testing in the cloudMobile testing in the cloud
Mobile testing in the cloud
 
Prezentarea ta mai buna
Prezentarea ta mai bunaPrezentarea ta mai buna
Prezentarea ta mai buna
 
FiiPractic 2015 - Adroid Pro - Day 7 - Follow-up Day
FiiPractic 2015 - Adroid Pro - Day 7 - Follow-up DayFiiPractic 2015 - Adroid Pro - Day 7 - Follow-up Day
FiiPractic 2015 - Adroid Pro - Day 7 - Follow-up Day
 
FiiPractic 2015 - Adroid Pro - Day 5 - SQL Day
FiiPractic 2015 - Adroid Pro - Day 5 - SQL DayFiiPractic 2015 - Adroid Pro - Day 5 - SQL Day
FiiPractic 2015 - Adroid Pro - Day 5 - SQL Day
 
FiiPractic 2015 - Adroid Pro - Day 3 - API Day
FiiPractic 2015 - Adroid Pro - Day 3 - API DayFiiPractic 2015 - Adroid Pro - Day 3 - API Day
FiiPractic 2015 - Adroid Pro - Day 3 - API Day
 
FiiPractic 2015 - Adroid Pro - Day 1 - UI Day
FiiPractic 2015 - Adroid Pro - Day 1 - UI DayFiiPractic 2015 - Adroid Pro - Day 1 - UI Day
FiiPractic 2015 - Adroid Pro - Day 1 - UI Day
 

Performance tools Droidcon Eastern Europe

  • 5. Andrei Diaconu • Cofounder of Android Iași
  • 6. Andrei Diaconu • Cofounder of Android Iași • 5 years of Android
  • 7. Andrei Diaconu • Cofounder of Android Iași • 5 years of Android • Trainer & Speaker
  • 8.
  • 9. Why is my app dropping below 60fps?
  • 10. Why is my app dropping below 60fps? Why is my app draining the battery?
  • 11. Why is my app dropping below 60fps?
  • 12. Why is my app dropping below 60fps?
  • 13. Why is my app dropping below 60fps? • Simple list
  • 14. Why is my app dropping below 60fps? • Simple list • Items have some text
  • 15. Why is my app dropping below 60fps? • Simple list • Items have some text
  • 16. Why is my app dropping below 60fps? • Simple list • Items have some text • Scroll is not smooth
  • 17. • Scroll is not smooth
  • 18. • Scroll is not smooth Why?
  • 19. • Scroll is not smooth Why? Can we make sure?
  • 20. • Scroll is not smooth Why? Can we make sure?
  • 21. Can we make sure?
  • 22. Can we make sure?
  • 23. Can we make sure?
  • 24. Can we make sure?
  • 25.
  • 29. Frames 16ms line Time Choreographer: Skipped 34 frames! The application may be doing too much work on its main thread.
  • 30.
  • 32. Traceview • Measure how long each method takes to execute
  • 33. Traceview • Measure how long each method takes to execute • Analyse measurements using Traceview
  • 34. Traceview • Measure how long each method takes to execute
  • 35. Traceview //Start in OnResume
 Debug.startMethodTracing("bad_list"); • Measure how long each method takes to execute
  • 36. Traceview //Start in OnResume
 Debug.startMethodTracing("bad_list"); //Stop in OnPause
 Debug.stopMethodTracing(); • Measure how long each method takes to execute
  • 37. Traceview //Start in OnResume
 Debug.startMethodTracing("bad_list"); //Stop in OnPause
 Debug.stopMethodTracing(); //Grab using adb
 adb pull • Measure how long each method takes to execute
  • 38. Traceview //Start in OnResume
 Debug.startMethodTracing("bad_list"); //Stop in OnPause
 Debug.stopMethodTracing(); //Grab using adb
 adb pull • Measure how long each method takes to execute //Grab using adb
 adb pull /sdcard/bad_list.trace bad_list.trace
  • 39. Traceview //Start in OnResume
 Debug.startMethodTracing("bad_list"); //Stop in OnPause
 Debug.stopMethodTracing(); //Grab using adb
 adb pull • Measure how long each method takes to execute //Needs permission WRITE_EXTERNAL_STORAGE //Grab using adb
 adb pull /sdcard/bad_list.trace bad_list.trace
  • 40. Traceview //Start in OnResume
 Debug.startMethodTracing("bad_list"); //Stop in OnPause
 Debug.stopMethodTracing(); //Grab using adb
 adb pull • Measure how long each method takes to execute //Needs permission WRITE_EXTERNAL_STORAGE //Grab using adb
 adb pull /sdcard/bad_list.trace bad_list.trace
  • 41. Traceview • Measure how long each method takes to execute
  • 42. Traceview • Measure how long each method takes to execute
  • 43. Traceview • Measure how long each method takes to execute • Analyse measurements using Traceview• Analyse measurements using Traceview
  • 44. Traceview • Measure how long each method takes to execute • Analyse measurements using Traceview • Analyse measurements using Traceview
  • 45. Traceview • Measure how long each method takes to execute • Analyse measurements using Traceview • Analyse measurements using Traceview
  • 46. Traceview • Measure how long each method takes to execute • Analyse measurements using Traceview • Analyse measurements using Traceview
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 56.
  • 58. inflate() 4 x Html.fromHtml()
  • 59. @Override
 public View getView(int position, View convertView, ViewGroup parent) { 
 View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_jumpy_list, parent, false);
 
 TextView text1 = (TextView) view.findViewById(R.id.item_text1);
 TextView text2 = (TextView) view.findViewById(R.id.item_text2);
 TextView text3 = (TextView) view.findViewById(R.id.item_text3);
 TextView text4 = (TextView) view.findViewById(R.id.item_text4);
 
 String string1 = parent.getContext().getString(R.string.item_number_x, position);
 String string2 = parent.getContext().getString(R.string.item_description);
 String string3 = parent.getContext().getString(R.string.item_details);
 String string4 = parent.getContext().getString(R.string.item_related);
 
 text1.setText(Html.fromHtml(string1));
 text2.setText(Html.fromHtml(string2));
 text3.setText(Html.fromHtml(string3));
 text4.setText(Html.fromHtml(string4)); 
 return view;
 }
  • 60. @Override
 public View getView(int position, View convertView, ViewGroup parent) { 
 View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_jumpy_list, parent, false);
 
 TextView text1 = (TextView) view.findViewById(R.id.item_text1);
 TextView text2 = (TextView) view.findViewById(R.id.item_text2);
 TextView text3 = (TextView) view.findViewById(R.id.item_text3);
 TextView text4 = (TextView) view.findViewById(R.id.item_text4);
 
 String string1 = parent.getContext().getString(R.string.item_number_x, position);
 String string2 = parent.getContext().getString(R.string.item_description);
 String string3 = parent.getContext().getString(R.string.item_details);
 String string4 = parent.getContext().getString(R.string.item_related);
 
 text1.setText(Html.fromHtml(string1));
 text2.setText(Html.fromHtml(string2));
 text3.setText(Html.fromHtml(string3));
 text4.setText(Html.fromHtml(string4)); 
 return view;
 }
  • 61. @Override
 public View getView(int position, View convertView, ViewGroup parent) { 
 View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_jumpy_list, parent, false);
 
 TextView text1 = (TextView) view.findViewById(R.id.item_text1);
 TextView text2 = (TextView) view.findViewById(R.id.item_text2);
 TextView text3 = (TextView) view.findViewById(R.id.item_text3);
 TextView text4 = (TextView) view.findViewById(R.id.item_text4);
 
 String string1 = parent.getContext().getString(R.string.item_number_x, position);
 String string2 = parent.getContext().getString(R.string.item_description);
 String string3 = parent.getContext().getString(R.string.item_details);
 String string4 = parent.getContext().getString(R.string.item_related);
 
 text1.setText(Html.fromHtml(string1));
 text2.setText(Html.fromHtml(string2));
 text3.setText(Html.fromHtml(string3));
 text4.setText(Html.fromHtml(string4)); 
 return view;
 }
  • 62. @Override
 public View getView(int position, View convertView, ViewGroup parent) { 
 View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_jumpy_list, parent, false);
 
 TextView text1 = (TextView) view.findViewById(R.id.item_text1);
 TextView text2 = (TextView) view.findViewById(R.id.item_text2);
 TextView text3 = (TextView) view.findViewById(R.id.item_text3);
 TextView text4 = (TextView) view.findViewById(R.id.item_text4);
 
 String string1 = parent.getContext().getString(R.string.item_number_x, position);
 String string2 = parent.getContext().getString(R.string.item_description);
 String string3 = parent.getContext().getString(R.string.item_details);
 String string4 = parent.getContext().getString(R.string.item_related);
 
 text1.setText(Html.fromHtml(string1));
 text2.setText(Html.fromHtml(string2));
 text3.setText(Html.fromHtml(string3));
 text4.setText(Html.fromHtml(string4)); 
 return view;
 }
  • 63. @Override
 public View getView(int position, View convertView, ViewGroup parent) { 
 No recycling
 
 No View Holder
 
 
 Html.fromHtml is slow 
 return view;
 }
  • 64.
  • 65. But 200ms? Isn't this a bit much?
  • 66. But 200ms? Isn't this a bit much? Method tracking has a big impact itself
  • 67.
  • 73. Systrace It will run for 5 seconds Hit Ok and scroll the list
  • 74.
  • 75. Alert: Inflation during ListView recycling Time spent: 103.545 ms ListView items inflated: 20
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81. @Override
 public View getView(int position, View convertView, ViewGroup parent) {
 
 View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_jumpy_list, parent, false);
 
 
 
 TextView text1 = (TextView) view.findViewById(R.id.item_text1);
 TextView text2 = (TextView) view.findViewById(R.id.item_text2);
 TextView text3 = (TextView) view.findViewById(R.id.item_text3);
 TextView text4 = (TextView) view.findViewById(R.id.item_text4);
 
 
 String string1 = parent.getContext().getString(R.string.item_number_x, position);
 String string2 = parent.getContext().getString(R.string.item_description);
 String string3 = parent.getContext().getString(R.string.item_details);
 String string4 = parent.getContext().getString(R.string.item_related);
 
 
 text1.setText(Html.fromHtml(string1));
 text2.setText(Html.fromHtml(string2));
 text3.setText(Html.fromHtml(string3));
 text4.setText(Html.fromHtml(string4));
 
 
 return view;
 }
  • 82. @Override
 public View getView(int position, View convertView, ViewGroup parent) {
 Trace.beginSection("inflating");
 View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_jumpy_list, parent, false);
 Trace.endSection();
 
 Trace.beginSection("noViewHolder");
 TextView text1 = (TextView) view.findViewById(R.id.item_text1);
 TextView text2 = (TextView) view.findViewById(R.id.item_text2);
 TextView text3 = (TextView) view.findViewById(R.id.item_text3);
 TextView text4 = (TextView) view.findViewById(R.id.item_text4);
 Trace.endSection();
 
 String string1 = parent.getContext().getString(R.string.item_number_x, position);
 String string2 = parent.getContext().getString(R.string.item_description);
 String string3 = parent.getContext().getString(R.string.item_details);
 String string4 = parent.getContext().getString(R.string.item_related);
 
 Trace.beginSection("fromHtml");
 text1.setText(Html.fromHtml(string1));
 text2.setText(Html.fromHtml(string2));
 text3.setText(Html.fromHtml(string3));
 text4.setText(Html.fromHtml(string4));
 Trace.endSection();
 
 return view;
 }
  • 83.
  • 84.
  • 88.
  • 90. • obtainView = ~5ms • doFrame = ~20 * obtainView
  • 91. • obtainView = ~5ms • doFrame = ~20 * obtainView • each frame = ~100ms
  • 92. • obtainView = ~5ms • doFrame = ~20 * obtainView • each frame = ~100ms Alert: Inflation during ListView recycling Time spent: 103.545 ms ListView items inflated: 20
  • 93.
  • 94. Why is my app dropping below 60fps?
  • 95. Why is my app dropping below 60fps? Why is my app draining the battery?
  • 96. Why is my app draining the battery?
  • 97. Why is my app draining the battery? What is a wake lock?
  • 98. Why is my app draining the battery?
  • 99. Why is my app draining the battery? Battery Historian 2.0
  • 100. Why is my app draining the battery? Battery Historian 2.0
  • 101. Why is my app draining the battery? Battery Historian 2.0 adb bugreport > bugreport.txt
  • 102. Why is my app draining the battery? Battery Historian 2.0 adb bugreport > bugreport.txt go run battery-historian.go
  • 103. Why is my app draining the battery? Battery Historian 2.0 adb bugreport > bugreport.txt go run battery-historian.go open http://127.0.0.1:9999
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120. public static class UselessWorker {
 Runnable uselessWorker = new Runnable() {
 @Override
 public void run() {
 PowerManager pm = (PowerManager) BadApplication.instance
 .getSystemService(Context.POWER_SERVICE);
 PowerManager.WakeLock wakeLock = 
 pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "cool wakelock tag");
 wakeLock.acquire();
 
 //Some useless, but hard work
 
 wakeLock.release();
 try {
 Thread.sleep(45 * 1000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 } finally {
 work();
 }
 }
 };
 
 private void work() {
 new Thread(uselessWorker, "cool thread name").start();
 }
 } public static class UselessWorker {
 Runnable uselessWorker = new Runnable() {
 @Override
 public void run() {
 PowerManager pm = (PowerManager) BadApplication.instance
 .getSystemService(Context.POWER_SERVICE);
 PowerManager.WakeLock wakeLock = 
 pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "cool wakelock tag");
 wakeLock.acquire();
 
 //Some useless, but hard work
 
 wakeLock.release();
 try {
 Thread.sleep(45 * 1000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 } finally {
 work();
 }
 }
 };
 
 private void work() {
 new Thread(uselessWorker, "cool thread name").start();
 }
 }
  • 121. public static class UselessWorker {
 Runnable uselessWorker = new Runnable() {
 @Override
 public void run() {
 PowerManager pm = (PowerManager) BadApplication.instance
 .getSystemService(Context.POWER_SERVICE);
 PowerManager.WakeLock wakeLock = 
 pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "cool wakelock tag");
 wakeLock.acquire();
 
 //Some useless, but hard work
 
 wakeLock.release();
 try {
 Thread.sleep(45 * 1000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 } finally {
 work();
 }
 }
 };
 
 private void work() {
 new Thread(uselessWorker, "cool thread name").start();
 }
 } public static class UselessWorker {
 Runnable uselessWorker = new Runnable() {
 @Override
 public void run() {
 PowerManager pm = (PowerManager) BadApplication.instance
 .getSystemService(Context.POWER_SERVICE);
 PowerManager.WakeLock wakeLock = 
 pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "cool wakelock tag");
 wakeLock.acquire();
 
 //Some useless, but hard work
 
 wakeLock.release();
 try {
 Thread.sleep(45 * 1000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 } finally {
 work();
 }
 }
 };
 
 private void work() {
 new Thread(uselessWorker, "cool thread name").start();
 }
 }
  • 122. public static class UselessWorker {
 Runnable uselessWorker = new Runnable() {
 @Override
 public void run() {
 PowerManager pm = (PowerManager) BadApplication.instance
 .getSystemService(Context.POWER_SERVICE);
 PowerManager.WakeLock wakeLock = 
 pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "cool wakelock tag");
 wakeLock.acquire();
 
 //Some useless, but hard work
 
 wakeLock.release();
 try {
 Thread.sleep(45 * 1000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 } finally {
 work();
 }
 }
 };
 
 private void work() {
 new Thread(uselessWorker, "cool thread name").start();
 }
 } public static class UselessWorker {
 Runnable uselessWorker = new Runnable() {
 @Override
 public void run() {
 PowerManager pm = (PowerManager) BadApplication.instance
 .getSystemService(Context.POWER_SERVICE);
 PowerManager.WakeLock wakeLock = 
 pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "cool wakelock tag");
 wakeLock.acquire();
 
 //Some useless, but hard work
 
 wakeLock.release();
 try {
 Thread.sleep(45 * 1000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 } finally {
 work();
 }
 }
 };
 
 private void work() {
 new Thread(uselessWorker, "cool thread name").start();
 }
 }
  • 123. public static class UselessWorker {
 Runnable uselessWorker = new Runnable() {
 @Override
 public void run() {
 PowerManager pm = (PowerManager) BadApplication.instance
 .getSystemService(Context.POWER_SERVICE);
 PowerManager.WakeLock wakeLock = 
 pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "cool wakelock tag");
 wakeLock.acquire();
 
 //Some useless, but hard work
 
 wakeLock.release();
 try {
 Thread.sleep(45 * 1000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 } finally {
 work();
 }
 }
 };
 
 private void work() {
 new Thread(uselessWorker, "cool thread name").start();
 }
 } public static class UselessWorker {
 Runnable uselessWorker = new Runnable() {
 @Override
 public void run() {
 PowerManager pm = (PowerManager) BadApplication.instance
 .getSystemService(Context.POWER_SERVICE);
 PowerManager.WakeLock wakeLock = 
 pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "cool wakelock tag");
 wakeLock.acquire();
 
 //Some useless, but hard work
 
 wakeLock.release();
 try {
 Thread.sleep(45 * 1000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 } finally {
 work();
 }
 }
 };
 
 private void work() {
 new Thread(uselessWorker, "cool thread name").start();
 }
 }