Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PERFMATTERS for Android - DroidCon VIenna 2016

Hasan Hosgel
September 12, 2016

PERFMATTERS for Android - DroidCon VIenna 2016

The slogan '#PERFMATTERS' by Colt McAnlis is one of the most important statements, which an Android developer should follow. A well performing application makes the difference between a nice looking application and one, which gets successful. You, as an Android developer, have the responsibility to delight your users, so they don't feel how much work your application has to burden to fulfill the user's needs. This session will show you some easy optimizations and how to avoid glitches in the application. A lot of developers would shout, that this is premature optimization. In contrary it is preventive. With a small amount of work while developing you can avoid a lot of pitfalls. You will hopefully have a better understanding of the underlying system afterwards. During the session some tools and frameworks will be presented for helping you to fulfill your mission.

Hasan Hosgel

September 12, 2016
Tweet

More Decks by Hasan Hosgel

Other Decks in Technology

Transcript

  1. #DroidconAT #PERFMATTERS for Android | Hasan Hosgel Immobilien Scout GmbH

    Location: Berlin Employees: ~ 520 > 850.000 ads per month > 787 M visits in 2014* > 6 M Android downloads *source: comScore Digital Analytix, January 2015, complete IS24 (Portal & Mobile)
  2. #DroidconAT User Expectations Mobile App Users are impatient • 61%

    app start < 4 s Source: https://ssl.www8.hp.com/ww/en/secure/pdf/4aa5-7696enw.pdf
  3. #DroidconAT User Expectations Mobile App Users are impatient • 61%

    app start < 4 s • 49% app start < 2 s Source: https://ssl.www8.hp.com/ww/en/secure/pdf/4aa5-7696enw.pdf
  4. #DroidconAT User Expectations Mobile App Users are impatient • 61%

    app start < 4 s • 49% app start < 2 s Users are intolerant of issues and are quick to uninstall mobile apps Source: https://ssl.www8.hp.com/ww/en/secure/pdf/4aa5-7696enw.pdf
  5. #DroidconAT User Expectations Mobile App Users are impatient • 61%

    app start < 4 s • 49% app start < 2 s Users are intolerant of issues and are quick to uninstall mobile apps • 80% three attempts or less Source: https://ssl.www8.hp.com/ww/en/secure/pdf/4aa5-7696enw.pdf
  6. #DroidconAT User Expectations Mobile App Users are impatient • 61%

    app start < 4 s • 49% app start < 2 s Users are intolerant of issues and are quick to uninstall mobile apps • 80% three attempts or less • 53% apps with severe issues like crashes, freezes or errors Source: https://ssl.www8.hp.com/ww/en/secure/pdf/4aa5-7696enw.pdf
  7. #DroidconAT User Expectations Mobile App Users are impatient • 61%

    app start < 4 s • 49% app start < 2 s Users are intolerant of issues and are quick to uninstall mobile apps • 80% three attempts or less • 53% apps with severe issues like crashes, freezes or errors • 36% heavy battery usage Source: https://ssl.www8.hp.com/ww/en/secure/pdf/4aa5-7696enw.pdf
  8. #DroidconAT User Expectations Users blame the app and the company

    who made it Source: https://ssl.www8.hp.com/ww/en/secure/pdf/4aa5-7696enw.pdf
  9. #DroidconAT User Expectations Users blame the app and the company

    who made it • 55% app is responsible for performance issues Source: https://ssl.www8.hp.com/ww/en/secure/pdf/4aa5-7696enw.pdf
  10. #DroidconAT User Expectations Users blame the app and the company

    who made it • 55% app is responsible for performance issues • 37% Stated that app crashes or errors make them think less of a company’s brand Source: https://ssl.www8.hp.com/ww/en/secure/pdf/4aa5-7696enw.pdf
  11. #DroidconAT Performance Impacts 500 ms delay bounce rate -4.7% --

    conversion rate -1.9% Source: http://www.mobilejoomla.com/media/press/responsive-vs-serverside/Responsive-Design-vs- Server-Side-Solutions-Infographic.jpg
  12. #DroidconAT Performance Impacts 500 ms delay bounce rate -4.7% --

    conversion rate -1.9% 1,000 ms delay Source: http://www.mobilejoomla.com/media/press/responsive-vs-serverside/Responsive-Design-vs- Server-Side-Solutions-Infographic.jpg
  13. #DroidconAT Performance Impacts 500 ms delay bounce rate -4.7% --

    conversion rate -1.9% 1,000 ms delay bounce rate -8.3% -- Conversion rate -3.5% Source: http://www.mobilejoomla.com/media/press/responsive-vs-serverside/Responsive-Design-vs- Server-Side-Solutions-Infographic.jpg
  14. #DroidconAT Performance Impacts 500 ms delay bounce rate -4.7% --

    conversion rate -1.9% 1,000 ms delay bounce rate -8.3% -- Conversion rate -3.5% 100ms delay mean for Amazon -1% revenue Source: http://www.mobilejoomla.com/media/press/responsive-vs-serverside/Responsive-Design-vs- Server-Side-Solutions-Infographic.jpg
  15. #DroidconAT Performance Impacts 500 ms delay bounce rate -4.7% --

    conversion rate -1.9% 1,000 ms delay bounce rate -8.3% -- Conversion rate -3.5% 100ms delay mean for Amazon -1% revenue 11% scream at their device Source: http://www.mobilejoomla.com/media/press/responsive-vs-serverside/Responsive-Design-vs- Server-Side-Solutions-Infographic.jpg
  16. #DroidconAT Performance Impacts 500 ms delay bounce rate -4.7% --

    conversion rate -1.9% 1,000 ms delay bounce rate -8.3% -- Conversion rate -3.5% 100ms delay mean for Amazon -1% revenue 11% scream at their device 4 % throw their phones Source: http://www.mobilejoomla.com/media/press/responsive-vs-serverside/Responsive-Design-vs- Server-Side-Solutions-Infographic.jpg https://www.flickr.com/photos/9009139@N08/1263954 439
  17. #DroidconAT Possible improvements CPU Memory I/O • Keep the work

    of the main thread à ANR • Avoid GPU overdrawings • https://www.youtube.com/watc h?v=T52v50r-JfE
  18. #DroidconAT Possible improvements CPU Memory I/O • Keep the work

    of the main thread à ANR • Avoid GPU overdrawings • https://www.youtube.com/watc h?v=T52v50r-JfE • Avoid nested multi-pass layouts • http://goo.gl/Q5te24
  19. #DroidconAT Possible improvements CPU Memory I/O • Keep the work

    of the main thread à ANR • Avoid GPU overdrawings • https://www.youtube.com/watc h?v=T52v50r-JfE • Avoid nested multi-pass layouts • http://goo.gl/Q5te24 • Consider RenderScript for performance critical code
  20. #DroidconAT Setup LeakCanary debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1’ build.gradle public class

    DcAtApplication extends Application { @Override public void onCreate() { super.onCreate(); LeakCanary.install(this); } } DcAtApplication.java
  21. #DroidconAT Possible improvements CPU Memory I/O • Do not allocate

    memory inside onDraw() • Avoid Leaks • Avoid listener à EventBus
  22. #DroidconAT Possible improvements CPU Memory I/O • Do not allocate

    memory inside onDraw() • Avoid Leaks • Avoid listener à EventBus • Use SparseArray* family instead of JDK Collections/ Maps
  23. #DroidconAT Possible improvements CPU Memory I/O • Do not allocate

    memory inside onDraw() • Avoid Leaks • Avoid listener à EventBus • Use SparseArray* family instead of JDK Collections/ Maps • Be aware that enums need more resource, but use them, if it will make sense for you
  24. #DroidconAT Possible improvements CPU Memory I/O • Activate gzip compression

    on incoming and outgoing network traffic or FlatBuffer
  25. #DroidconAT Possible improvements CPU Memory I/O • Activate gzip compression

    on incoming and outgoing network traffic or FlatBuffer • Cache data on disk (image, http responses) with reasonable TTL
  26. #DroidconAT Possible improvements CPU Memory I/O • Activate gzip compression

    on incoming and outgoing network traffic or FlatBuffer • Cache data on disk (image, http responses) with reasonable TTL • Server side cache headers like ETag & Last-Modified
  27. #DroidconAT Possible improvements CPU Memory I/O • Activate gzip compression

    on incoming and outgoing network traffic or FlatBuffer • Cache data on disk (image, http responses) with reasonable TTL • Server side cache headers like ETag & Last-Modified • Use JobScheduler API to batch across system or better use push notifications for update information
  28. #DroidconAT Optimizing ArrayList public List<String> getDcAtNames(List<Attendee> attendees) { List<String> names

    = new ArrayList<>(); for (Attendee attendee : attendees) { names.add(attendee.name); } return names; } JAVA
  29. #DroidconAT Optimizing ArrayList public List<String> getDcAtNames(List<Attendee> attendees) { List<String> names

    = new ArrayList<>(attendees.size()); for (Attendee attendee : attendees) { names.add(attendee.name); } return names; } JAVA
  30. #DroidconAT Optimizing ArrayList @Override public boolean add(E object) { Object[]

    a = array; int s = size; if (s == a.length) { Object[] newArray = new Object[s + (s < (MIN_CAPACITY_INCREMENT / 2) ? MIN_CAPACITY_INCREMENT : s >> 1)]; System.arraycopy(a, 0, newArray, 0, s); array = a = newArray; } a[s] = object; size = s + 1; modCount++; return true; } JAVA
  31. #DroidconAT Optimizing Bundle public static DcAtScheduleFragment instance(int startMode) { final

    DcAtScheduleFragment fragment = new DcAtScheduleFragment(); final Bundle bundle = new Bundle(); bundle.putInt(START_MODE, startMode); fragment.setArguments(bundle); return fragment; } JAVA
  32. #DroidconAT Optimizing Bundle public static DcAtScheduleFragment instance(int startMode) { final

    DcAtScheduleFragment fragment = new DcAtScheduleFragment(); final Bundle bundle = new Bundle(1); bundle.putInt(START_MODE, startMode); fragment.setArguments(bundle); return fragment; } JAVA
  33. #DroidconAT Optimizing StringBuilder public StringBuilder getDcAtNames(List<String> names) { StringBuilder builder

    = new StringBuilder(); for (String name : names) { if (builder.length() > 0) { builder.append(", "); } builder.append(name); } return builder; } JAVA
  34. #DroidconAT Optimizing StringBuilder public StringBuilder getDcAtNames(List<String> names) { StringBuilder builder

    = new StringBuilder(names.size() * 13); for (String name : names) { if (builder.length() > 0) { builder.append(", "); } builder.append(name); } return builder; } JAVA
  35. #DroidconAT Optimizing StringBuilder final void append0(char[] chars) { int newCount

    = count + chars.length; if (newCount > value.length) { enlargeBuffer(newCount); } System.arraycopy(chars, 0, value, count, chars.length); count = newCount; } JAVA
  36. #DroidconAT Optimizing StringBuilder public StringBuilder addDcAtOrganizer(StringBuilder names, List<String> organizers) {

    names.ensureCapacity(names.length() + organizers.size() * 13); for (String organizer : organizers) { if (names.length() > 0) { names.append(", "); } names.append(organizer); } } JAVA
  37. #DroidconAT Optimizing Moar – The Loop public StringBuilder addDcAtOrganizer(StringBuilder names,

    List<String> organizers) { names.ensureCapacity(names.length() + organizers.size() * 13); for (String organizer : organizers) { if (names.length() > 0) { names.append(", "); } names.append(organizer); } } JAVA
  38. #DroidconAT Optimizing Moar – The Loop public StringBuilder addDcAtOrganizer(StringBuilder names,

    List<String> organizers) { names.ensureCapacity(names.length() + organizers.size() * 13); for (int i = 0; i < organizers.size(); i++) { String organizer = organizers.get(i); if (names.length() > 0) { names.append(", "); } names.append(organizer); } } JAVA
  39. #DroidconAT Optimizing Moar – The Loop public StringBuilder addDcAtOrganizer(StringBuilder names,

    List<String> organizers) { names.ensureCapacity(names.length() + organizers.size() * 13); for (int i = 0, organizersSize = organizers.size(); i < organizersSize; i++) { String organizer = organizers.get(i); if (names.length() > 0) { names.append(", "); } names.append(organizer); } } JAVA
  40. #DroidconAT Optimizing Moar – The Loop public StringBuilder addDcAtOrganizer(StringBuilder names,

    List<String> organizers) { final int size = organizers.size(); names.ensureCapacity(names.length() + size * 13); for (int i = 0; i < size; i++) { String organizer = organizers.get(i); if (names.length() > 0) { names.append(", "); } names.append(organizer); } } JAVA
  41. #DroidconAT Optimizing Moar – The Loop public StringBuilder addDcAtOrganizer(StringBuilder names,

    List<String> organizers) { final int size = organizers.size(); names.ensureCapacity(names.length() + size * 13); for (int i = 0; i < size; i++) { String organizer = organizers.get(i); names.append(organizer); names.append(", "); } names.substring(0, names.length()-1); } JAVA
  42. #DroidconAT Optimizing Much Moar – Method Invocation public void onViewCreated(View

    view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); text.setTextColor(attendee.isOrganizer() ? getResources().getColor(R.color.accent) : getResources().getColor(R.color.black)); avatar.setImageResource(attendee.getAvatar()); welcomeText.setText(getString( R.string.hello_world, attendee.name)); } JAVA
  43. #DroidconAT Optimizing Much Moar – Method Invocation public void onViewCreated(View

    view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); final Resources res = getResources(); text.setTextColor(attendee.isOrganizer() ? res.getColor(R.color.accent) : res.getColor(R.color.black)); avatar.setImageResource(attendee.getAvatar()); welcomeText.setText(getString( R.string.hello_world, attendee.name)); } JAVA
  44. #DroidconAT Optimizing Much Moar – Method Invocation public void onViewCreated(View

    view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); final Resources res = getResources(); text.setTextColor(attendee.isOrganizer() ? res.getColor(R.color.accent) : res.getColor(R.color.black)); avatar.setImageResource(attendee.getAvatar()); welcomeText.setText(res.getString( R.string.hello_world, attendee.name)); } JAVA
  45. #DroidconAT Optimizing Access Methods private Attendee attendee; public void onViewCreated(View

    view, Bundle savedInstanceState) { button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { makeText(getContext(), getWelcomeTextFor(attendee.getName()), LENGTH_SHORT).show(); } }); } private String getWelcomeTextFor(String name) { return getResources().getString(R.string.welcome_text, name); } JAVA
  46. #DroidconAT Finding Access Methods https://github.com/JakeWharton/dex-method-list $ ./build/dex-method-list src/test/resources/one.apk … package.DcAtScheduleFragment

    access$000(DcAtScheduleFragment ) package.DcAtScheduleFragment access$100(DcAtScheduleFragment , String) … CL
  47. #DroidconAT Optimizing Access Methods Attendee attendee; public void onViewCreated(View view,

    Bundle savedInstanceState) { button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { makeText(getContext(), getWelcomeTextFor(attendee.getName()), LENGTH_SHORT).show(); } }); } String getWelcomeTextFor(String name) { return getResources().getString(R.string.welcome_text, name); } JAVA
  48. #DroidconAT www.immobilienscout24.de Contact: +HasanHosgel alosdev Thanks for attending! We are

    Hiring! http://www.immobilienscout24.de/jobs https://speakerdeck.com/alosdev/perfmatters-for-android- droidcon-berlin-2016
  49. #DroidconAT www.immobilienscout24.de Contact: +HasanHosgel alosdev Thanks for attending! We are

    Hiring! http://www.immobilienscout24.de/jobs https://speakerdeck.com/alosdev/perfmatters-for-android- droidcon-berlin-2016
  50. #DroidconAT Sources • https://ssl.www8.hp.com/ww/en/secure/pdf/4aa5-7696enw.pdf • http://www.mobilejoomla.com/media/press/responsive-vs- serverside/Responsive-Design-vs-Server-Side-Solutions- Infographic.jpg • https://speakerdeck.com/jakewharton/eliminating-code-overhead-

    square-hq-2015 • http://periplanisi.com/android/2013/11/multi-pass-viewgroup- and-performance/ • https://slideshare.net/dougsillars/android-app-performance- europe-2015 • https://www.youtube.com/playlist?list=PLWz5rJ2EKKc9CBxr3BVjPT PoDPLdPIFCE