$30 off During Our Annual Pro Sale. View Details »

Engineering Android apps for Performance & Quality

Paresh Mayani
December 27, 2015

Engineering Android apps for Performance & Quality

Delivered this talk on android best practices/do's/don'ts in GDG DevFest Ahmedabad 2015 event.

P.S. There are many best practices you can follow for improving your application's quality and performance, but these are the do's, don'ts and best practices I have noted/observed by reviewing applications of start-ups, stackoverflow Q/As, company projects, etc.

Paresh Mayani

December 27, 2015
Tweet

More Decks by Paresh Mayani

Other Decks in Technology

Transcript

  1. Engineering Android apps for Performance &
    Quality
    Do’s, Don’ts and best practices
    +PareshMayani
    @pareshmayani

    View Slide

  2. Outline
    - Scalability
    - Maintainable
    - Easily adoptable
    - Proper architecture
    - App testing
    Performance Quality
    - Optimizing app performance
    using tools
    - Removing unused resources
    - Using XML drawables & Vectors
    - Compressing and Caching data
    - Loading and Syncing images
    - Proper API design

    View Slide

  3. #PerfMatters

    View Slide

  4. Improving layout performance
    1. Optimizing layout hierarchies
    2. Reusable layouts
    3. Compound drawables

    View Slide

  5. Optimizing layout hierarchies
    Each widget and layout you add to your application requires initialization,
    layout, and drawing.
    Avoid deep hierarchy of views
    How to optimize layout?
    ● Inspect your layout
    ● Revise your layout
    Use Hierarchy Viewer

    View Slide

  6. Using Hierarchy Viewer
    Inspect layout using
    Hierarchy viewer tool

    View Slide

  7. Using Hierarchy Viewer
    Revise your layout and again inspect
    using Hierarchy viewer tool

    View Slide

  8. Using Hierarchy Viewer
    Hierarchy Viewer shows three times:
    ● Measure
    ● Layout
    ● Draw

    View Slide

  9. Reusable layouts
    Define a common layout and reuse it with
    It’s powerful as it allows you create reusable complex layouts.
    For example,

    View Slide

  10. Compound drawables
    Lint warning => “This tag and its children can be replaced by one
    and a compound drawable”
    A LinearLayout which contains an ImageView and a TextView can be more
    efficiently handled as a compound drawable.
    TextView supports 4 compound drawables
    ● drawableLeft
    ● drawableRight
    ● drawableTop
    ● drawableBottom

    View Slide

  11. android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:contentDescription="@string/text"
    android:src="@drawable/ic_launcher" />
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/text" />

    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:drawableLeft="@drawable/ic_launcher"
    android:text="@string/text" />
    Bad practice of designing layout Compound drawable

    View Slide

  12. Optimizing and lowering GPU Overdraw
    Debug GPU Overdraw using the developer options
    http://developer.android.
    com/tools/performance/debug-gpu-overdraw/index.
    html

    View Slide

  13. Optimizing and lowering GPU Overdraw
    Image source: http://developer.android.com/tools/performance/debug-gpu-overdraw/index.html

    View Slide

  14. Optimizing and lowering GPU Overdraw
    Image source: http://developer.android.com/tools/performance/debug-gpu-overdraw/index.html

    View Slide

  15. Use UI thread for only UI
    It should not happen on main UI thread:
    ● Networking (request/response)
    ● Images (loading images and syncing)
    ● Querying large set of data from Database
    Then what should I do?
    ● Use loaders for the database access
    ● Use Retrofit, OkHttp for networking

    View Slide

  16. Removing unused resources
    The Gradle build system for Android supports "resource shrinking": the
    automatic removal of resources that are unused, at build time, in the packaged
    app.
    Also removes resources from libraries you are depending on if they are not
    actually needed by your application

    View Slide

  17. android {
    ...
    buildTypes {
    release {
    minifyEnabled true
    shrinkResources true
    proguardFiles getDefaultProguardFile('proguard-android.txt'),
    'proguard-rules.pro'
    }
    }
    }

    View Slide

  18. android {
    ...
    buildTypes {
    release {
    minifyEnabled true
    shrinkResources true
    proguardFiles getDefaultProguardFile('proguard-android.txt'),
    'proguard-rules.pro'
    }
    }
    }
    To turn on code shrinking
    To turn on resource shrinking

    View Slide

  19. > gradlew clean assembleDebug --info > output_file.txt
    :app:shrinkDebugResources (Thread[Task worker Thread 2,5,main]) started.
    :app:shrinkDebugResources
    Skipped unused resource res/anim/abc_fade_in.xml: 396 bytes
    Skipped unused resource res/mipmap-xhdpi-v4/ic_launcher.png: 5233 bytes
    Removed unused resources: Binary resource data reduced from 4010KB to 2906KB: Removed 27%
    Note: If necessary, you can disable resource shrinking by adding
    android {
    buildTypes {
    debug {
    shrinkResources false
    }

    View Slide

  20. Warning:
    Removing unused
    resources
    Warning:
    1. tools:keep
    2. tools:discard
    3. tools:shrinkMode
    tools:keep
    when using shrinkMode="strict", you can specify specific resources to
    keep (typically because they are referenced in an indirect way via runtime
    code, such as Resources#getIdentifier(some dynamically computed
    resource name).
    tools:discard
    When using resource shrinking to automatically strip out unused
    resources, you can specify specific resources to discard (typically
    because the resource is referenced in some way that you know does not
    affect your app
    tools:shrinkMode
    When using resource shrinking to automatically strip out unused
    resources, you can specify whether the Gradle plugin should play it safe
    and whitelist all resources that might be referenced via a getIdentifier
    lookup from string resources

    View Slide

  21. Removing unused resources
    Tip:
    Removing unused resources that lint identifies is still useful because removing
    them:
    ● Speeds up your build
    ● Reduces your project's maintenance burden.

    View Slide

  22. Caching Data
    Effective cache controls will dramatically reduce server load
    Cache data as much as possible, why?
    - Less number of web requests => No use of network radio => Improved
    battery life
    - Important: It will make user busy in reading something while loading new
    set of data

    View Slide

  23. private void fetchGitHubContributors() {
    App.getInstance().getGithub().getContributors(Const.GITHUB_ORGA, Const.GITHUB_REPO, new
    Callback() {
    @Override
    public void success(final ContributorList contributors, retrofit.client.Response response) {
    mAdapter.addAll(contributors);
    App.getInstance().getModelCache().putAsync(Const.CACHE_KEY_FRISBEE_CONTRIBUTORS,
    contributors, DateTime.now().plusDays(1), null);
    }
    });
    }
    For an example, check ModelCache of GDG Frisbee app: https://goo.gl/HHKfMI

    View Slide

  24. Image optimization
    Do you fetch images from the server every time?
    Cache decoded images - One of the best way to display images quickly
    There are some libraries available: Picasso, Glide, Fresco
    Scale down bitmaps
    Use Nine Patch image
    Try to create drawables via XML if possible
    Use Vector images

    View Slide

  25. Load image(s) priority wise
    Note: Not a performance tip but a good practice in loading UI
    Picasso library provides functionality to prioritize the image loading through
    priority().
    priority() takes one of three constants, HIGH, MEDIUM, or LOW

    View Slide

  26. Picasso
    .with(context)
    .load(myAdapter.exampleImages[0])
    .fit()
    .priority(Picasso.Priority.HIGH)
    .into(imageViewHero);
    Picasso
    .with(context)
    .load(myAdapter.exampleImages[0])
    .fit()
    .priority(Picasso.Priority.LOW)
    .into(imageViewDetail);

    View Slide

  27. XML drawables
    Are you using lots of images?
    You can achieve some of the images by creating XML.
    Creating an image with XML is very cheap and it is more efficient.
    Using a 500 kb background image or using an Xml drawable which has size of
    just 400 bytes?

    View Slide

  28. Use Vectors
    One of the benefits of using vectors in Android is Scalability (No need to put
    different size of drawable images)
    VectorDrawable (Added in API 21)
    Problem: OutOfMemory exception while animation-list (Use case in next slide)
    Can animate vector drawables easily

    View Slide

  29. Use case: Using
    Use case: One drawable is having 2-3 animated portions into it
    30 images each set
    Each image is of 320*480 resolution
    Bytes per pixel, typically 4 (32 bits)
    1 image = 320*480*4 bytes which will be 614,000 bytes
    30 frames (images) = 614,000 * 30 = 18420000
    1 set = 18420000 bytes
    If 3 set then total 55260000 bytes = 55.26 MB to hold raw bitmap data of all frames

    View Slide

  30. Use case: Using
    Use case: One drawable is having 2-3 animated portions into it
    30 images each set
    Each image is of 320*480 resolution
    Bytes per pixel, typically 4 (32 bits)
    1 image = 320*480*4 bytes which will be 614,000 bytes
    30 frames (images) = 614,000 * 30 = 18420000
    1 set = 18420000 bytes
    If 3 set then total 55260000 bytes = 55.26 MB to hold raw bitmap data of all frames
    55.26 MB??
    Congrats for OutOfMemoryException

    View Slide

  31. Use case: Using
    Use case: One drawable is having 2-3 animated portions into it
    30 images each set
    Each image is of 320*480 resolution
    Bytes per pixel, typically 4 (32 bits)
    1 image = 320*480*4 bytes which will be 614,000 bytes
    30 frames (images) = 614,000 * 30 = 18420000
    1 set = 18420000 bytes
    If 3 set then total 55260000 bytes = 55.26 MB to hold raw bitmap data of all frames
    55.26 MB??
    Congrats for OutOfMemoryException
    Reason: Heap memory limit exceeded
    Keep in mind:
    16 MB/24 MB/32 MB

    View Slide

  32. Use Vectors
    Problem: OutOfMemory exception while animation-list (Use case in next slide)
    Solution:
    Use vector drawable (AnimatedVectorDrawable)

    View Slide

  33. android:height="64dp" android:width="64dp"
    android:viewportHeight="600" android:viewportWidth="600">
    android:name="rotationGroup"
    android:pivotX="300.0"
    android:pivotY="300.0"
    android:rotation="45.0" >
    android:name="v"
    android:fillColor="#000000"
    android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />


    android:drawable="@drawable/vectordrawable" >
    android:name="rotationGroup"
    android:animation="@anim/rotation" />
    android:name="v"
    android:animation="@anim/path_morph" />

    android:duration="6000"
    android:propertyName="rotation"
    android:valueFrom="0"
    android:valueTo="360" />
    animated_vd.xml
    rotation.xml
    vectordrawable.xml

    View Slide

  34. Parsing JSON response
    Because Parsing has a performance effect
    Small JSON - GSON
    Large JSON - Jackson
    GSON or Jackson increases code readability

    View Slide

  35. Effective API Design
    Send only required fields and avoid unnecessary details
    Most of the time enemy is Select * query
    Can optimize APIs with “Expiry date” or “Last updated” date

    View Slide

  36. External libraries, be careful!
    Good libraries provide documentation/example
    Who knows developers behind library has written solid code!!
    Test before integrate https://medium.com/@orhanobut/test-before-integrate-e713090070d6#.
    ian7jqalo

    View Slide

  37. Remember to remove your preview tags
    Case 1: It would be fine If the image is only loaded once but what if the sample
    image is on item layout
    Case 2: It would be fine if android:text attribute is set successfully with the
    server response. What if it would not, “Demo text”?

    View Slide

  38. Tools attribute
    tools:ignore
    tools:targetApi
    tools:locale
    tools:context
    tools:layout
    tools:listitem / listheader / listfooter
    tools:showIn
    tools:menu
    tools:actionBarNavMode

    View Slide

  39. android:text="John Doe"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
    tools:text="John Doe"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
    Using tools:text attribute

    View Slide

  40. #QualityMatters

    View Slide

  41. Version Control System
    Project should be done under version control system
    Open source projects are using Git
    Follow Git branching work
    ● Gitflow workflow
    ● Feature branch workflow
    Follow development process via PR(Pull Requests)

    View Slide

  42. PR, Code Review & Continuous Integration
    Submits PR
    Do Code Review
    on PR
    PR triggers a build of
    the project on CI server
    Merge if build of a
    PR successful
    Developers
    Code review comments

    View Slide

  43. Continuous Integration
    CI should perform below tasks:
    ● Perform static analysis
    ● Run unit tests
    ● Run functional tests
    ● Check code coverage report

    View Slide

  44. Static Code/Resource Analysis
    Helps you finding issues in your code before you ship it to production
    Which are the tools available? => Android Lint, SonarQube, FB Infer, etc.
    The lint tool checks your Android project source files for potential bugs and
    optimization improvements for correctness, security, performance, usability,
    accessibility, and internationalization
    Select Analyze => Inspect code...

    View Slide

  45. Static Code/Resource Analysis

    View Slide

  46. Testing matters a lot...
    Unit Testing Tests that are designed to ensure the smallest
    divisible pieces of code (units or components)
    are working the way they were intended.
    Typically placed in the app/src/test/java folder.
    Instrumentation testing Android Instrumentation is a set of "hooks" into
    the Android system that allow you to control the
    lifecycle of Android components
    Typically placed in the app/src/androidTest/java
    folder.

    View Slide

  47. Testing/Mocking frameworks
    Robolectric
    JUnit
    Espresso
    Robotium
    Mockito
    EasyMock, PowerMock

    View Slide

  48. Code Coverage
    How to know how much code has been covered through Unit test?
    Use tool like JaCoCo (Java Code Coverage)
    JaCoCo gives detailed report (graphical) of code coverage

    View Slide

  49. Code Coverage

    View Slide

  50. Code Coverage
    Image source: http://softwarecave.org/2014/02/01/using-junit-jacoco-and-maven-for-code-coverage/

    View Slide

  51. Don’t wait for users to submit crash reports
    You would not come to know about crashes being faced by users, until they
    submit voluntarily
    Then how to get it automatically?
    Use tools like Crashlytics, Crittercism, ACRA

    View Slide

  52. Architecture best practices

    View Slide

  53. Why Architecture best practices?
    Have you heard about?
    Scalability
    Easily adoptable
    Maintainable

    View Slide

  54. Follow architecture pattern
    MVC (Model View Controller)
    MVP (Model View Presenter)
    MVVM (Model View View Model)

    View Slide

  55. Managing signing configs efficient way
    Don’t include signingConfigs in your build.gradle file, because it would be
    available in the version control system
    Efficient way:
    Include it in gradle.properties and don’t include it in version control system

    View Slide

  56. Manage dependencies in effective way
    1. Create a dependencies.gradle file in the root of the project and include all
    the required permissions
    2. Apply the this dependencies gradle file in build.gradle of root project
    apply from: 'dependencies.gradle'
    3. Refer required dependencies in module(s)

    View Slide

  57. Manage dependencies in effective way
    dependencies.gradle at
    root level
    module level build.gradle
    apply dependencies.gradle in build.
    gradle at root level

    View Slide

  58. Follow android code styles all the time
    How?
    Use some static code analysis tools like SonarQube or Checkstyle
    http://checkstyle.sourceforge.net/

    View Slide

  59. Naming convention
    How?
    Follow the convention of prefixing the type, as in type_foo_bar.xml.
    Examples:
    ● fragment_contact_details.xml
    ● view_primary_button.xml
    ● activity_main.xml.

    View Slide

  60. All the styles in single file? Wait...
    Split a large file into different files like:
    ● styles.xml
    ● app_theme.xml
    Check GDG Frisbee for the example: https://github.com/gdg-x/frisbee

    View Slide

  61. Localization - an easy way
    How?
    Do you know strings.xml?
    Define a string with common name but
    different values in different values
    folder

    View Slide

  62. Strings.xml - best practice
    Bad
    CALL FAILED
    Good
    Call failed

    View Slide

  63. Conclusion
    - Analyse and optimize application performance
    - Have an awesome architecture followed
    - Have an awesome UI/UX
    - Remove unused code/resources
    - Testing matters a lot!
    Follow best practices and standards but… but…
    - Don’t over engineer
    - Work with framework, not against!

    View Slide

  64. Resources
    https://www.youtube.com/playlist?list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE
    https://plus.google.com/communities/116342551728637785407
    https://www.udacity.com/course/android-performance--ud825
    http://artemzin.com/blog/android-development-culture-the-document-qualitymatters/
    http://www.curious-creature.com/docs/android-performance-case-study-1.html
    http://developer.android.com/tools/performance/hierarchy-viewer/profiling.html
    http://saulmm.github.io/squeezing-gradle-builds/

    View Slide

  65. Thanks
    +PareshMayani
    @pareshmayani

    View Slide

  66. Wait...Wait…Bonus Tip

    View Slide

  67. Delight your user (See you in next talk)

    View Slide