Date post: | 21-Jan-2017 |
Category: |
Technology |
Upload: | zeljko-plesac |
View: | 431 times |
Download: | 0 times |
ANDROID NOWADAYS
1.4 billion users
23 SDK versions
1,294 device vendors with
24,093 distinct Android devices
I believe that the details will define the difference between good and really amazing. We prefer amazing.
- ANA BAOTIĆ
PROVIDE A BETTER CRASH EXPERIENCEYou should try to minimise your crashes.
Optimise your apps in a way you are able to detect crashes
even before they occur.
public class DataUtils {
public boolean testMethod(String test){ return test == null && test.length() == 0; } }
BUILD YOUR OWN “STATIC CODE CHECKERS” - USE CUSTOM LINT RULES
• define custom Lint rules that are best suited to your needs
• user/project/team specific
WRITE TESTS
• black box tests, integration tests, UI tests, unit tests…
• TDD
• lot of tools - Espresso, Robolectric, Mockito…
HANDLE FAILURES
• all failed tests have to be examined carefully
• if your code didn’t cause them, ignore them but test them
once again when new version of testing platform is available
CONTINOUS INTEGRATION
Automate static code checkers & tests execution
A many products available - Jenkins, Travis, CircleCI…
MEMORY LEAKS
• they will cause problems and crash your applications
• many great tools for detection
A memory leak detection library for Android and Java,
developed by Square (Pierre-Yves Ricau).
LEAK CANARY
• detects memory leaks in your
application, external libraries,
even Android OS itself
• it will not give you an answer
what the cause of a leak is, just
the information that the leak has
occurred
ANDROID STUDIO MEMORY PROFILERS
• Memory monitor, Heap and Allocation Trackers
• introduced in Android Studio 2.0
• can help you investigate memory leaks
ENFORCE RULES
• don’t block the main thread - even regular users will notice
flickering
• get familiar with multithreading components
• use Traceview and dmtracedump
STRICT MODE
• use Strict mode in debug builds - set penalty death • detectDiskReads() • detectDiskWrites()
DETECT ANR’S
• ANRWatchDog (link) • detects Android ANRs (Application Not
Responding) problems • can either crash your application or notify you via
callback
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
• returning null values is evil
public class Person {
private String name;
private String surname;
public Person(String name, String surname) { this.name = name; this.surname = surname; }
… }
public static String getFullName(Person person) { if(person != null){
return person.getName() + person.getSurname(); }
else{ return null;
} }
public static String getFullName(Person person) { if (person == null) { throw new IllegalStateException("Person cannot be null!”); }
return person.getName() + person.getSurname(); }
LOG AND MEASURE YOUR CRASHES
• many great tools (Crashlytics, AppsDynamics, Crittercism)
• analyse your crashes • custom ROMs causing crashes? • cheap, low quality devices? • frequency of crashes?
THE TRY-CATCH BLOCK AND EXCEPTIONS• you should care about your handled exceptions
• they have to be logged and analysed
• should contain useful information
public class ProfilePresenterImpl implements ProfilePresenter{
public void showPersonData() { view.showFullName(PersonUtils.getFullName(person))); view.showBirthday(PersonUtils.getFormattedBirthday(person))); view.hideLoadingDialog();
} }
public class ProfilePresenterImpl implements ProfilePresenter{
public void showPersonData() { String fullName = PersonUtils.getFullName(person));
if(fullName != null){ view.showFullName(PersonUtils.getFullName(person)));
}
view.showBirthday(PersonUtils.getFormattedBirthday(person))); view.hideLoadingDialog();
} }
public class ProfilePresenterImpl implements ProfilePresenter{
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.printStackTrace();
view.showErrorDialog(); }
} }
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); } }}
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()); } }
public class ProfilePresenterImpl implements ProfilePresenter{
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(); }
} }
APP CRASH HANDLERS
• define custom app crash handler in everyone of your
production builds
• avoid ugly system dialogs
• watch out for app restart loops!
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
APPLICATION CLASS
@Overridepublic void onCreate() { super.onCreate(); Thread.setDefaultUncaughtExceptionHandler(new AppCrashHandler(this)); }
MultiWindow support, Jack compiler, new APIs, deprecated
APIs, new programming languages…
ANDROID IS GETTING NEW FEATURES.
Thank you!
Visit www.infinum.co or find us on social networks:
infinum.co infinumco infinumco infinum
@ZELJKOPLESAC [email protected]