Slide 1

Slide 1 text

10 ways to improve your app's performance Boris Farber Developer Advocate Google

Slide 2

Slide 2 text

Data Intensive apps ● Long launch time ● Janky scrolling ● Unresponsive app

Slide 3

Slide 3 text

IF YOU HAVE A SMALL APP FORGET THESE SLIDES

Slide 4

Slide 4 text

1 - Activity leaks

Slide 5

Slide 5 text

Activity

Slide 6

Slide 6 text

Why memory leaks are dangerous ● Holding references to unused Activity ● Activity holds its layout ==> holds all views

Slide 7

Slide 7 text

Listeners leak public class LeakActivity extends Activity { // ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); NastyManager.getInstance().addListener(this); // ...

Slide 8

Slide 8 text

Listener's leak + fix @Override public void onDestroy() { super.onDestroy(); NastyManager.getInstance().removeListener(this); } remove listener

Slide 9

Slide 9 text

Static References ● Activities/fragments etc - they have a life cycle ● Activity will not be GC-ed ● Static references ○ become dangling "pointers" ○ m_staticActivity = staticFragment.getActivity()

Slide 10

Slide 10 text

Activity

Slide 11

Slide 11 text

2 - Activity leaks

Slide 12

Slide 12 text

Outer class (Activity) Inner class (Handler)

Slide 13

Slide 13 text

This is a leak public class MainActivity extends Activity { // ... Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... handler = new Handler() { @Override public void handleMessage(Message msg) { } }; // ...

Slide 14

Slide 14 text

What happens if ... handler.postDelayed(...)

Slide 15

Slide 15 text

This is a leak + fix private static class MyHandler extends Handler { private final WeakReference mActivity; // ... public MyHandler(MainActivity activity) { mActivity = new WeakReference(activity); // ... } @Override public void handleMessage(Message msg) { } // ... }

Slide 16

Slide 16 text

Outer class (Activity) Inner class (Handler)

Slide 17

Slide 17 text

Prefer static to non static inner classes ● Non static Handler --> Activity leak ● Both classes have a different lifetime

Slide 18

Slide 18 text

What you can do Activity Leaks ● Remove away static references ● Use event bus ● Unregister listeners ● Prefer static inner classes to non static ones

Slide 19

Slide 19 text

What you can do Activity Leaks ● Do code reviews ● Understand your app structure ● Use tools (MAT ...) ● Print logs on callbacks

Slide 20

Slide 20 text

3 - Use UI thread only for UI

Slide 21

Slide 21 text

Not on UI thread ● Images (caching, loading) ● Networking ● JSON ● Database access

Slide 22

Slide 22 text

Not on UI thread ● Images (caching, loading) ● Networking ● JSON ● Database access Use Loaders Use libraries

Slide 23

Slide 23 text

UI thread Looper.myLooper() == Looper.getMainLooper()

Slide 24

Slide 24 text

4 - Use libraries

Slide 25

Slide 25 text

Images ● Glide ● Picasso ● Fresco ● ... Different design tradeoffs, especially around large images count

Slide 26

Slide 26 text

Memory ● Bitmaps are tricky ○ Large size ○ Fragmented heap ○ ... ● LRUCache - part of the support library

Slide 27

Slide 27 text

Networking ● Tricky APIs ● Many java.net API calls are blocking ○ Streams ○ Equals of URL class result in DNS call

Slide 28

Slide 28 text

Networking/Async Http ● OkHttp - part of Android (from 4.4) ● Volley ● Retrofit - rest calls

Slide 29

Slide 29 text

5 - Large JSONs

Slide 30

Slide 30 text

Large JSON ● Parsing has a performance effect ● Converted to class with getters and setters

Slide 31

Slide 31 text

JSON ● Small JSONs - GSON is the best ● Large JSONs - Jackson, ig-json-parser

Slide 32

Slide 32 text

What you can do Scrolling ● Keep UI thread only for UI ● Understand concurrency APIs (next bullet) ● Use libraries (memory, caching, json ...) ● Use loaders

Slide 33

Slide 33 text

6 - Concurrency APIs

Slide 34

Slide 34 text

Service ● Service methods run on UI thread ! ● Consider ○ IntentService ○ AsyncTask ○ Executors ○ HandlerThreads, Handlers and Loopers - Appendix

Slide 35

Slide 35 text

IntentService ● Single threaded ● Simple/One job in a time ● No job system (keep track for jobs) ● No way to stop it

Slide 36

Slide 36 text

AsyncTask ● Don't care about result outside of UI ● Activity lifecycles - can cause a memory leak (rotation) ● Changes rapidly (grab latest and add to your project)

Slide 37

Slide 37 text

Executor Framework ● Thread pool ● Callbacks ● Futures ● MapReduce tasks

Slide 38

Slide 38 text

What you can do Concurrency API ● Understand the APIs and tradeoffs ● Refactor

Slide 39

Slide 39 text

7 - System abuse

Slide 40

Slide 40 text

System Abuse ● Don't call private APIs by reflection ● Don't call private native methods (NDK/C level) ● Don't use Runtime.exec ● "adb shell am" to communicate with other process is not something we want to support

Slide 41

Slide 41 text

8 - Deprecation

Slide 42

Slide 42 text

Deprecation ● API will be removed ● Your app will not work ● No way to update APIs and tools

Slide 43

Slide 43 text

Deprecation ● There is a compelling reason to move ○ Security ○ Correctness ○ Performance

Slide 44

Slide 44 text

What you can do around deprecation ● Know and use APIs ● Refactor your dependencies

Slide 45

Slide 45 text

Don't use Apache Http Connection ● Removed at M (still available as dependency) ● Use HttpURLConnection ○ Simple API ○ Small size ○ Transparent compression ○ Response caching

Slide 46

Slide 46 text

What you can do Deprecation ● Don't abuse the system ● Update your dependencies and tools

Slide 47

Slide 47 text

9 - Bring your own gloves

Slide 48

Slide 48 text

Bring your own gloves ● Various versions, devices, OEMs ● APIs and libraries shipped with platform might behave differently ● Async task ...

Slide 49

Slide 49 text

Bring your own gloves ● Consider bundling your own version ● Check dex limit ● Check code bloat

Slide 50

Slide 50 text

Security ● Own wrapped library (SSL/crypto etc') ● Rooted devices ● Your own sensitive data/protocols

Slide 51

Slide 51 text

10 - Architecture

Slide 52

Slide 52 text

Understand app components life cycle ● Activities ● Fragments ● Tasks ● Flags ● Add logs on callbacks

Slide 53

Slide 53 text

Work with framework not against ... ● Framework components have a purpose ○ Specific semantics ○ Used when those semantics are desired ● Don't over engineer ● Keep simple

Slide 54

Slide 54 text

Pick 3rd party lib checklist ● Solves your problem ● Plays nicely with your current dependencies ● Dex method count ● Dependencies ● Maintenance ● Runtime permissions

Slide 55

Slide 55 text

Design your app for ● Sleeping most of the time ● Responsive when "awaken"

Slide 56

Slide 56 text

What you can do Architecture ● Consistent ● Get people on board quickly ● Have someone experienced ● Pick your dependencies wisely

Slide 57

Slide 57 text

Boris Farber www.api-solutions.com @BorisFarber

Slide 58

Slide 58 text

Appendix Loopers/Handlers

Slide 59

Slide 59 text

HandlerThread ● A thread with a message box ● Saves a lot of boilerplate code ● Uses Looper

Slide 60

Slide 60 text

Loopers and Handlers ● Looper ○ Synchronized message queue to process messages from handlers ○ Takes the next task, executes it, then takes the next one and so on ○ One looper per thread ● Handler ○ Set of methods to post messages

Slide 61

Slide 61 text

Inside Looper (Android src) private Looper(boolean quitAllowed) { // ... mThread = Thread.currentThread(); } /** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ public static void loop() { final Looper me = myLooper(); // ... for (; ; ) { // ... } infinite loop