Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

#PerfMatters

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

Using Hierarchy Viewer Inspect layout using Hierarchy viewer tool

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

Bad practice of designing layout Compound drawable

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

> 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 }

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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.

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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);

Slide 27

Slide 27 text

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?

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

animated_vd.xml rotation.xml vectordrawable.xml

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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”?

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

Using tools:text attribute

Slide 40

Slide 40 text

#QualityMatters

Slide 41

Slide 41 text

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)

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

Static Code/Resource Analysis

Slide 46

Slide 46 text

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.

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

Code Coverage

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

Architecture best practices

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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)

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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.

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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!

Slide 64

Slide 64 text

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/

Slide 65

Slide 65 text

Thanks +PareshMayani @pareshmayani

Slide 66

Slide 66 text

Wait...Wait…Bonus Tip

Slide 67

Slide 67 text

Delight your user (See you in next talk)