Top Banner
Don’t go crashing my heart ŽELJKO PLESAC
55

Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

Apr 16, 2017

Download

Software

Infinum
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

Don’t go crashing my heart

ŽELJKO PLESAC

Page 2: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

ANDROID NOWADAYS

• more than 1.4 billions of users

• 23 different SDK versions

• 1,294 device vendors with more than 24,093 distinct

Android devices

Page 3: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

YOUR USERS DESERVE BEAUTIFUL APPLICATIONS, WITH BEST POSSIBLE USER

EXPERIENCE.

Page 4: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

CRASHES HAVE ENORMOUS AFFECT ON USER

EXPERIENCE.

Page 5: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

NOBODY LIKES CRASHES*.

* EXPECT TESTERS

Page 6: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

PROVIDE BETTER CRASH EXPERIENCE

• you should care about your crashes and try to minimise

them

• optimise your applications in a way, that you can detect

crash even before it occurs

Page 7: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

01USE STATIC CODE CHECKERS & WRITE TESTS

Page 8: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

Strict rules• use at least default set of rules

• enforce zero tolerance to all static

code checker warnings and

errors

• aim for high test code coverage

• don’t test only for positive

outcomes, test also for negative

• write stress tests

• always insert at least one test

which will throw an exception or

bug

• all tests have to pass before

merging into development

Page 9: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

TESTS STABILITY? Test frameworks have bugs. CI servers also. Android platform also.

Page 10: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

HANDLING FAILED TESTS

• all failed tests have to be carefully examined

• if they are not caused by your code, ignore them but test

them once again when new version of testing platform is

available

• this doesn’t mean that everything is not your fault

Page 11: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

03USE CONTINUOUS INTEGRATION

Page 12: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

CONTINOUS INTEGRATION

• static code checkers & tests automation

• a lot of available products - Jenkins, Travis, CircleCI…

• use protected branches for master and development branch

• use Git flow (or some other pattern)

Page 13: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

04HANDLE COMMON ANDROID PROBLEMS - MEMORY LEAKS

Page 14: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

MEMORY LEAKS

• they will cause problems and crash your applications

• a lot of great tools

Page 15: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

A memory leak detection library for Android and Java,

developed by Square (Pierre-Yves Ricau).

De facto standard for detecting memory leaks, use it in your

debug builds.

LEAK CANARY

Page 16: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

• detects memory leaks in your

application, external libraries,

event Android OS itself

• it will not give you an answer

what is the cause of a leak, just

an information that the leak has

occurred

Page 17: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

WEAK REFERENCES ARE NOT THE ANSWER TO

EVERYTHING.

Page 18: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

05CRASH FAST

Page 19: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

CRASH YOU APPLICATIONS AS SOON AS POSSIBLE

• Square’s approach to handling crashes (presentation and

video)

• organise your code in a way that it crashes as soon as

possible

• use exceptions

• null values are evil

Page 20: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

package co.infinum.crashhandler.sampleapp;

/** * Created by Željko Plesac on 13/03/16. */ public class Person {

private String name;

private String surname;

public Person(String name, String surname) { this.name = name; this.surname = surname; }

public String getName() { return name; }

public void setName(String name) { this.name = name; }

public String getSurname() { return surname; }

public void setSurname(String surname) { this.surname = surname; } }

Page 21: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

package co.infinum.crashhandler.sampleapp;

/** * Created by Željko Plesac on 13/03/16. */ public class PersonUtils {

private PersonUtils() {

}

public static String getFullName(Person person) { return person.getName() + person.getSurname(); } }

Page 22: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

package co.infinum.crashhandler.sampleapp;

/** * Created by Željko Plesac on 13/03/16. */ public class PersonUtils {

private PersonUtils() {

}

public static String getFullName(Person person) { if(person != null){

return person.getName() + person.getSurname(); }

else{ return null;

} } }

Page 23: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

package co.infinum.crashhandler.sampleapp;

/** * Created by Željko Plesac on 13/03/16. */ public class PersonUtils {

private PersonUtils() {

}

public static String getFullName(Person person) { if (person == null) { throw new IllegalStateException("Person cannot be null!”); }

return person.getName() + person.getSurname(); } }

Page 24: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

06LOG AND MEASURE

Page 25: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

LOG AND MEASURE YOUR CRASHES

• lot of great tools (Crashlytics, AppsDynamics, Crittercism)

• analyse your crashes • are crashes happening on custom ROMs? • are crashes occurring only on cheap phones? • are your crashes frequent?

Page 26: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum
Page 27: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

I don’t care about warnings, only errors.

- KING HENRIK VIII.

Page 28: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

TRY-CATCH BLOCK AND EXCEPTIONS

• you should care about your handled exceptions

• they have to be logged and analysed

• should contain useful information

Page 29: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

package co.infinum.crashhandler.sampleapp;

/** * Created by Željko Plesac on 13/03/16. */ public class ProfilePresenterImpl implements ProfilePresenter{

private Person person;

private ProfileView view;

public ProfilePresenterImpl(Profile person){ this.person = person;

} …

public void showPersonData() { view.showFullName(PersonUtils.getFullName(person))); view.showBirthday(PersonUtils.getFormattedBirthday(person))); view.hideLoadingDialog();

} }

Page 30: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

package co.infinum.crashhandler.sampleapp;

/** * Created by Željko Plesac on 13/03/16. */ public class ProfilePresenterImpl implements ProfilePresenter{

private Person person;

private ProfileView view;

public ProfilePresenterImpl(Profile person){ this.person = person;

} …

public void showPersonData() { String fullName = PersonUtils.getFullName(person));

if(fullName != null){ view.showFullName(PersonUtils.getFullName(person)));

}

view.showBirthday(PersonUtils.getFormattedBirthday(person))); view.hideLoadingDialog();

} }

Page 31: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

package co.infinum.crashhandler.sampleapp;

/** * Created by Željko Plesac on 13/03/16. */ public class ProfilePresenterImpl implements ProfilePresenter{

private Person person;

private ProfileView view;

public ProfilePresenterImpl(Profile person){ this.person = person;

} …

public void showPersonData() { try{

String fullName = PersonUtils.getFullName(person)); if(fullName != null){ view.showFullName(PersonUtils.getFullName(person)));

}

view.showBirthday(PersonUtils.getFormattedBirthday(person))));} } catch(Exception e){ e.prinStackTrace();

view.showErrorDialog(); }

} }

Page 32: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

TIMBER

• Utility on top of Android's normal Log class

• by Jake Wharton

Page 33: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

Timber.plant(new Timber.DebugTree());

Timber.d(...) Timber.i(...) Timber.v(...) Timber.e(...) Timber.w(...) Timber.wtf(...)

Page 34: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

CRASH REPORTING TREE

private static class CrashReportingTree extends Timber.Tree { @Override protected void log(int priority, String tag, String message, Throwable t) { if (priority == Log.VERBOSE || priority == Log.DEBUG) { return; } // will write to the crash report but NOT to logcat Crashlytics.log(message); if (t != null) { Crashlytics.logException(t); } }}

Page 35: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

CRASH REPORTING TREE

@Overridepublic void onCreate() { super.onCreate(); CrashlyticsCore crashlyticsCore = new CrashlyticsCore.Builder()

.disabled(BuildConfig.DEBUG).build(); Fabric.with(this, new Crashlytics.Builder().core(crashlyticsCore).build());

if (BuildConfig.DEBUG) { Timber.plant(new Timber.DebugTree()); } else { Timber.plant(new CrashReportingTree()); } }

Page 36: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

package co.infinum.crashhandler.sampleapp;

/** * Created by Željko Plesac on 13/03/16. */ public class ProfilePresenterImpl implements ProfilePresenter{

private Person person;

private ProfileView view;

public ProfilePresenterImpl(Profile person){ this.person = person;

} …

public void showPersonData() { try{

String fullName = PersonUtils.getFullName(person)); if(fullName != null){ view.showFullName(PersonUtils.getFullName(person)));

}

view.showBirthday(PersonUtils.getFormattedBirthday(person))));} } catch(Exception e){ Timber.e(e, “Failure in “ + getClass().getSimpleName());

view.showErrorDialog(); }

} }

Page 37: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

/** * Logs everything to crashlytics, then we just need to log an exception and we should see all prior logs online! */ private static class RemoteDebuggingTree extends Timber.Tree {

@Override protected void log(int priority, String tag, String message, Throwable t) { // will write to the crash report as well to logcat Crashlytics.log(priority, tag, message);

if (t != null) { Crashlytics.logException(t); } } }

Page 38: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

08HIDE CRASHES FROM YOUR USERS

Page 39: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

Crashes are just exceptions, which are not handled by your application*.

* IN MOST CASES

Page 40: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

APP CRASH HANDLERS

• define custom app crash handler in all of your production

builds

• avoid ugly system dialogs

• simple configuration

• apps are restarted, so they go into stable state

• watch for cyclic bugs!

Page 41: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

public class AppCrashHandler implements Thread.UncaughtExceptionHandler { private Activity liveActivity; public AppCrashHandler(Application application) { application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() { @Override public void onActivityResumed(Activity activity) { liveActivity = activity; } @Override public void onActivityPaused(Activity activity) { liveActivity = null; } }); } @Override public void uncaughtException(Thread thread, Throwable ex) { if(liveActivity != null){ Intent intent = new Intent(getApplicationContext(), MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); liveActivity.finish(); liveActivity.startActivity(intent); } System.exit(0); } }

CUSTOM CRASH HANDLER

Page 42: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

APPLICATION CLASS

@Overridepublic void onCreate() { super.onCreate(); Thread.setDefaultUncaughtExceptionHandler(new AppCrashHandler(this)); }

Page 43: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

EXAMPLE

Page 44: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

08USE STAGED ROLLOUTS

Page 45: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

STAGED ROLLOUT

• can only be used for app updates, not when publishing an

app for the first time

• your update reaches only a percentage of your users, which

you can increase over time

Page 46: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

STAGED ROLLOUT PROCESS ①

• at first, define that your update is only available to small

percentage of your users (I.E. 5%)

• closely monitor crash reports and user feedback • users receiving the staged rollout can leave public

reviews on Google Play

• if everything goes OK, increase the percentage

• if you get negative feedback or encounter some bugs, halt

the process and fix all of reported problems

Page 47: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

10HARSH TRUTH

Page 48: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

YOUR APPS WILL CRASH IN PRODUCTION, AND THERE IS

NOTHING YOU CAN DO TO PREVENT IT.

Page 49: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

THERE IS NO SUCH THING AS 100% CRASH FREE ANDROID APPLICATION

• large number of different devices

• large number of OS versions • in most cases, proposed minimum API value is 15 and

the current stable version is 23, which means that your

app has to work on 8 different API versions

• device vendors alter Android OS - they add custom

solutions and bloatware

• rooted Android devices - core functionalities can be altered

Page 50: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

THINGS ARE GOING TO BECOME EVEN MORE

COMPLICATED.

Page 51: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

Phones, tablets, phablets, freezers, smartwatches, cars, bikes,

boards….

ANDROID IS EXPANDING.

Page 52: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

MultiWindow support, Jack compiler, new APIs, deprecated

APIs, new programming languages…

ANDROID IS GETTING NEW FEATURES.

Page 53: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

THAT’S THE BEAUTY OF ANDROID.

Page 54: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

DEVELOPERS WILL ALWAYS FIND A WAY.

Page 55: Android Meetup Slovenia #5 - Don't go crashing my heart by Zeljko Plesac, Infinum

Thank you!

Visit www.infinum.co or find us on social networks:

infinum.co infinumco infinumco infinum

TWITTER: @ZELJKOPLESAC EMAIL: [email protected]