10 ways to improve your android app performance

Post on 07-Aug-2015

1.717 Views

Category:

Mobile

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

10 ways to improve your app performanceBoris Farber Developer Advocate

+borisfarber @borisfarber www.api-solutions.com

IF YOU HAVE A SMALL APP FORGET THESE SLIDES

Symptoms

● Long start time● Slow app● Janky scrolling● Irresponsive app

Activity Leaks

Why memory leaks are dangerous

● Holding references to unused Activity○ handlers + static variables

● Activity holds its view

● Activities/fragments etc - they have a life cycle● Static references

○ become dangling "pointers"○ staticActivity = staticFragment.getActivity()○ hold chain of references that lead to Activity <==

MEMORY LEAK

Outer class (Activity)

Inner class (Handler)

This is leakpublic class LeakActivity extends Activity {// ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); NastyManager.getInstance().addListener(this);// ...

This is leak + fix@Overridepublic void onDestroy() { super.onDestroy();

NastyManager.getInstance().removeListener(this);}

remove listener

This is leakpublic class MainActivity extends Activity {

// ...

Handler handler; @Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

// ...

handler = new Handler() {

@Override

public void handleMessage(Message msg) {

} };

// ...

What happens if ...

handler.postDelayed(...)

This is leak + fix

private static class MyHandler extends Handler {

private final WeakReference<MainActivity> mActivity;

// ...

public MyHandler(MainActivity activity) {

mActivity = new WeakReference<MainActivity>(activity);

// ...

}

@Override

public void handleMessage(Message msg) {

}

// ...

}

Outer class (Activity)

Inner class (Handler)

Prefer static to non static inner classes

● Non static Handler --> Activity leak● Both classes have a different lifetime

3 ways to handle

● Use event bus● Unregister listeners● Prefer static inner classes to non static

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

Activity LeaksQuestions ?

Scrolling

Use UI Thread only for UI

● JSON parsing● Memory (images)● Networking● Database access

What you can do to speed up scrolling

● Memory access - use library (caching, loading)● Networking access -

○ use library○ revisit your concurrency model

● Database access - use loaders

● JSON - use library DO NOT DO ANYTHING ON UI THREAD

JSON

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

Large JSON

● Parsing has a performance effect● When converted to class with getters and

setters

UI thread

Looper.myLooper() == Looper.getMainLooper()

UI thread

● Never block it● Many java.net APIs are blocking

○ Streams○ Equals of URL class result in DNS call○ HttpURLConnection

Don't over sync

● When user doesn't need it● Use push notifications

Scrolling Questions ?

Concurrency APIs 1

Service

● Service methods run on UI thread ! ● Consider

○ IntentService○ AsyncTask○ Executors (separate bullet)○ HandlerThreads, Handlers and Loopers (separate

bullet)● Libraries do it for you

IntentService

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

AsyncTask

● Consider Loaders (part of support library)● 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)

Concurrency APIs 1 Questions ?

Deprecation

Deprecation

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

Deprecation

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

What you can do around deprecation

● Know and use APIs● Refactor your dependencies

Newer is better

● Prefer Toolbar to ActionBar● Prefer RecyclerView (especially for

animations)

Don't use Apache Http Connection

● Removed at M (still available as dependency)

● Use HttpURLConnection○ Simple APIa○ Small size○ Transparent compression○ Response caching

DeprecationQuestions ?

JNI

Best

● Use JNI as part of 3rd party lib

Media

● Explore advanced CPU features● Memory ● Audio● Video

Security

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

What you can do

● Calls are expensive● Keep the boundaries simple● Keep native code to minimum● Keep native code isolated

○ All native methods in same class or package○ Porting layer

● Test, test, test ...

JNIquestions?

Architecture

Understand app components life cycle

● Activities● Fragments● Tasks● Flags

● Add logs on callbacks

Work with framework not against ...

● Framework components have a purpose○ Specific semantics○ Used when those semantics are desired

● Don't over engineer● Keep simple

Your architecture

● Consistent● Get people on board quickly● Have someone experienced

Design your app for

● Sleeping most of the time● Responsive when "awaken"

Architecturequestions?

Concurrency APIs 2

ExecutorService

Executor Framework

● Thread pool● Callbacks● Futures

Dispatch downloadsExecutorService executor = Executors.newFixedThreadPool(1);// ...public void performAsyncCall(Handler handler) throws Exception{ // Fire a request. Future<Response> response = executor.submit(new Request (new URL("https://www.google.co.uk/")));

// Do your tasks here // ...

Dispatch downloads// ...

// block current thread

InputStream body = response.get().getBody();

// System.out.print(getStringFromInputStream(body));

// post result to handler

Message message = new Message();

Bundle bundle = new Bundle();

bundle.putString("text", "New data");

message.setData(bundle);

handler.sendMessage(message);

}

// ...

executor.shutdown();

Parse resultspublic static class Request implements Callable<Response> {

private URL url;

public Request(URL url) {

this.url = url;

System.out.println("On async http dispatcher thread " + Thread.currentThread().getId());

}

@Override

public Response call() throws Exception {

System.out.println("On worker thread from pool " + Thread.currentThread().getId());

return new Response(url.openStream());

}

}

Parse resultspublic static class Response {

private InputStream body;

public Response(InputStream body) {

this.body = body;

}

public InputStream getBody() {

System.out.println("On async http dispatcher thread " + Thread.currentThread().getId());

return body;

}

}

Executor Framework

● Excellent for mapreduce jobs

Handlers and Loopers

HandlerThread

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

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● Handler

○ Set of methods to post messages

Parse results// Has Handler in own thread, will batch update the main Activity

private class MyLooper extends Thread {

@Override

public void run() {

// Prepare the current thread to loop for events

Looper.prepare();

dispatcherThreadHandler = new Handler() {

@Override

public void handleMessage(Message msg) {

...

}

};

Looper.loop();

}

Push handler to any other thread

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 (; ; ) { // ...

}

Concurrency APIs 2Questions ?

Miscellany

Pick 3rd party lib checklist

● Solves your problem● Plays nicely with your current dependencies● Dex method count● Dependencies● Maintenance● Runtime permissions

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

Avoid complex views

● Visual clutter● Harder to maintain and draw● Use HierarchyViewer

Use TimingLogging for measuring

Best of luck in your journey wherever Android takes you

Thank you !Boris FarberDeveloper Advocate

+borisfarber@borisfarberwww.api-solutions.com

top related