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

PERFMATTERS for Android - DroidCon Turin 2016

PERFMATTERS for Android - DroidCon Turin 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

April 07, 2016
Tweet

More Decks by Hasan Hosgel

Other Decks in Technology

Transcript

  1. www.immobilienscout24.de
    Hasan Hosgel – Droidcon Turin 2016
    #PERFMATTERS
    for Android

    View Slide

  2. #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)

    View Slide

  3. Why we are developers?

    View Slide

  4. Why we are developers?
    ESPECIALLY ANDROID

    View Slide

  5. Source: https://www.flickr.com/photos/theinfamousgdub/1765952198

    View Slide

  6. We are smart!
    Source: https://www.flickr.com/photos/theinfamousgdub/1765952198

    View Slide

  7. Source: http://giphy.com/gifs/apple-looney-tunes-android-4A41Wn7C32RiM

    View Slide

  8. We Love Android!
    Source: http://giphy.com/gifs/apple-looney-tunes-android-4A41Wn7C32RiM

    View Slide

  9. Source: Photo by Sujaki-F

    View Slide

  10. We have Passion!
    Source: Photo by Sujaki-F

    View Slide

  11. We have Passion!
    Source: Photo by Sujaki-F

    View Slide

  12. We have Passion!
    Source: Photo by Sujaki-F
    We Love Challenges

    View Slide

  13. Source: https://www.flickr.com/photos/[email protected]/6793826885

    View Slide

  14. We Love Money
    Source: https://www.flickr.com/photos/[email protected]/6793826885

    View Slide

  15. Source: http://agenciabrasil.ebc.com.br/geral/foto/2014-07/cerimonia-de-premiacao-da-copa-do-mundo-no-brasil

    View Slide

  16. We love to delight our
    users
    Source: http://agenciabrasil.ebc.com.br/geral/foto/2014-07/cerimonia-de-premiacao-da-copa-do-mundo-no-brasil

    View Slide

  17. User Expectations

    View Slide

  18. User Expectations
    Mobile App Users are impatient
    Source: https://ssl.www8.hp.com/ww/en/secure/pdf/4aa5-7696enw.pdf

    View Slide

  19. 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

    View Slide

  20. 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

    View Slide

  21. 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

    View Slide

  22. 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

    View Slide

  23. 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

    View Slide

  24. 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

    View Slide

  25. User Expectations
    Source: https://ssl.www8.hp.com/ww/en/secure/pdf/4aa5-7696enw.pdf

    View Slide

  26. 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

    View Slide

  27. 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

    View Slide

  28. 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

    View Slide

  29. Performance Impacts

    View Slide

  30. Performance Impacts
    500 ms delay
    Source: http://www.mobilejoomla.com/media/press/responsive-vs-serverside/Responsive-Design-vs-
    Server-Side-Solutions-Infographic.jpg

    View Slide

  31. 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

    View Slide

  32. 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

    View Slide

  33. 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

    View Slide

  34. 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

    View Slide

  35. 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 there device
    Source: http://www.mobilejoomla.com/media/press/responsive-vs-serverside/Responsive-Design-vs-
    Server-Side-Solutions-Infographic.jpg

    View Slide

  36. 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 there 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/
    [email protected]/1263954439

    View Slide

  37. View Slide

  38. Source: http://giphy.com/gifs/sad-kawaii-pretty-10XOyCb09KyjLy

    View Slide

  39. www.immobilienscout24.de
    Let‘s find some performance improvements

    View Slide

  40. Possible improvements
    CPU
    Memory
    I/O

    View Slide

  41. Possible improvements
    CPU
    Memory
    I/O

    View Slide

  42. Possible improvements
    CPU
    Memory
    I/O
    •  Keep the work of the main
    thread ! ANR

    View Slide

  43. Possible improvements
    CPU
    Memory
    I/O
    •  Keep the work of the main
    thread ! ANR
    •  Avoid GPU overdrawings
    • https://www.youtube.com/
    watch?v=T52v50r-JfE

    View Slide

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

    View Slide

  45. Possible improvements
    CPU
    Memory
    I/O
    •  Keep the work of the main
    thread ! ANR
    •  Avoid GPU overdrawings
    • https://www.youtube.com/
    watch?v=T52v50r-JfE
    •  Avoid nested multi-pass
    layouts
    • http://goo.gl/Q5te24
    •  Consider RenderScript for
    performance critical code

    View Slide

  46. Possible improvements
    CPU
    Memory
    I/O

    View Slide

  47. Possible improvements
    CPU
    Memory
    I/O
    •  Do not allocate memory inside
    onDraw()

    View Slide

  48. Possible improvements
    CPU
    Memory
    I/O
    •  Do not allocate memory inside
    onDraw()
    •  Avoid Leaks

    View Slide

  49. LeakCanary to the Rescue
    https://github.com/square/
    leakcanary

    View Slide

  50. 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 DcItApplication extends Application {
    @Override
    public void onCreate() {
    super.onCreate();
    LeakCanary.install(this);
    }
    }
    DcItApplication.java

    View Slide

  51. Use Your Debug Build Normally

    View Slide

  52. Analyze Memory

    View Slide

  53. Analyze Heap Dump

    View Slide

  54. Analyze Heap Dump

    View Slide

  55. Analyze Heap Dump since AS 1.5

    View Slide

  56. Analyze Memory

    View Slide

  57. Possible improvements
    CPU
    Memory
    I/O
    •  Do not allocate memory inside
    onDraw()
    •  Avoid Leaks
    •  Avoid listener ! EventBus

    View Slide

  58. 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

    View Slide

  59. 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

    View Slide

  60. Possible improvements
    CPU
    Memory
    I/O

    View Slide

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

    View Slide

  62. Analyze First Start

    View Slide

  63. Analyze Second Start

    View Slide

  64. Analyze Second Start

    View Slide

  65. 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

    View Slide

  66. Finally Second Start

    View Slide

  67. 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

    View Slide

  68. 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

    View Slide

  69. Source: http://www.flickr.com/photos/[email protected]/9172895225

    View Slide

  70. Optimizing ArrayList

    View Slide

  71. Optimizing ArrayList
    public List getDcItNames(List attendees) {
    List names = new ArrayList<>();
    for (Attendee attendee : attendees) {
    names.add(attendee.name);
    }
    return names;
    }
    JAVA

    View Slide

  72. Optimizing ArrayList
    public List getDcItNames(List attendees) {
    List names = new ArrayList<>(attendees.size());
    for (Attendee attendee : attendees) {
    names.add(attendee.name);
    }
    return names;
    }
    JAVA

    View Slide

  73. 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

    View Slide

  74. Optimizing ArrayList
    void addDcItSpeaker(ArrayList attendees, List speakers) {
    for (String speaker : speakers) {
    attendees.add(speaker);
    }
    }
    JAVA

    View Slide

  75. Optimizing ArrayList
    void addDcItSpeaker(ArrayList attendees, List speakers) {
    attendees.ensureCapacity(attendees.size() + speakers.size());
    for (String speaker : speakers) {
    attendees.add(speaker);
    }
    }
    JAVA

    View Slide

  76. Optimizing Bundle

    View Slide

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

    View Slide

  78. Optimizing Bundle
    public static DcItScheduleFragment instance(int startMode) {
    final DcItScheduleFragment fragment = new DcItScheduleFragment();
    final Bundle bundle = new Bundle(1);
    bundle.putInt(START_MODE, startMode);
    fragment.setArguments(bundle);
    return fragment;
    }
    JAVA

    View Slide

  79. Optimizing StringBuilder

    View Slide

  80. Optimizing StringBuilder
    public StringBuilder getDcItNames(List names) {
    StringBuilder builder = new StringBuilder();
    for (String name : names) {
    if (builder.length() > 0) {
    builder.append(", ");
    }
    builder.append(name);
    }
    return builder;
    }
    JAVA

    View Slide

  81. Optimizing StringBuilder
    public StringBuilder getDcItNames(List names) {
    StringBuilder builder = new StringBuilder(names.size() * 13);
    for (String name : names) {
    if (builder.length() > 0) {
    builder.append(", ");
    }
    builder.append(name);
    }
    return builder;
    }
    JAVA

    View Slide

  82. 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

    View Slide

  83. Optimizing StringBuilder
    public StringBuilder addDcItOrganizer(StringBuilder names, List organizers)
    {
    names.ensureCapacity(names.length() + organizers.size() * 13);
    for (String organizer : organizers) {
    if (names.length() > 0) {
    names.append(", ");
    }
    names.append(organizer);
    }
    }
    JAVA

    View Slide

  84. Optimizing Loops

    View Slide

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

    View Slide

  86. Optimizing Moar – The Loop
    public StringBuilder addDcItOrganizer(StringBuilder names, List 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

    View Slide

  87. Optimizing Moar – The Loop
    public StringBuilder addDcItOrganizer(StringBuilder names, List 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

    View Slide

  88. Optimizing Moar – The Loop
    public StringBuilder addDcItOrganizer(StringBuilder names, List 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

    View Slide

  89. Optimizing Method invocations

    View Slide

  90. 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

    View Slide

  91. 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

    View Slide

  92. 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

    View Slide

  93. Optimizing Access Methods

    View Slide

  94. 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

    View Slide

  95. Finding Access Methods
    https://github.com/JakeWharton/dex-method-list
    $ ./build/dex-method-list src/test/resources/one.apk

    package.DcItScheduleFragment access$000(DcItScheduleFragment )
    package.DcItScheduleFragment access$100(DcItScheduleFragment , String)

    CL

    View Slide

  96. 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

    View Slide

  97. Source: https://www.flickr.com/photos/marcus_t_ward/10715983613

    View Slide

  98. Source: http://www.bhmpics.com/success_kid-wallpapers.html

    View Slide

  99. Source: http://www.flickr.com/photos/[email protected]/5065834411/

    View Slide

  100. 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-turin-2016

    View Slide

  101. View Slide

  102. View Slide

  103. View Slide

  104. View Slide

  105. 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-turin-2016

    View Slide

  106. 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=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE

    View Slide