Avoid the "Force close" - standard way of application crash.
Setup a restart mechanism when the crash happens anyway.
See below how to do these:
Call Thread.setDefaultUncaughtExceptionHandler() in order to catch all uncaught exception, in which case uncaughtException() method will be called. "Force close" will not appear and the application will be unresponsive, which is not a quite good thing.
In order to restart your application when it crashed you should do the following :
In the onCreate method, in your main activity initialize a PendingIntent member:
Intent intent = PendingIntent.getActivity(
YourApplication.getInstance().getBaseContext(),
0,
new Intent(getIntent()),
getIntent().getFlags());
Then put the following in your uncaughtException() method:
You also must call System.exit(), otherwise will not work.
In this way your application will restart after 2 seconds.
Eventually you can set some flag in your intent that the application crashed and in your onCreate() method you can show a dialog "I'm sorry, the application crashed, hope never again :)".
public class MyExceptionHandler implements
java.lang.Thread.UncaughtExceptionHandler {
private final Context myContext;
private final Class<?> myActivityClass;
public MyExceptionHandler(Context context, Class<?> c) {
myContext = context;
myActivityClass = c;
}
public void uncaughtException(Thread thread, Throwable exception) {
StringWriter stackTrace = new StringWriter();
exception.printStackTrace(new PrintWriter(stackTrace));
System.err.println(stackTrace);// You can use LogCat too
Intent intent = new Intent(myContext, myActivityClass);
String s = stackTrace.toString();
//you can use this String to know what caused the exception and in which Activity
intent.putExtra("uncaughtException", "Exception is: " + stackTrace.toString());
intent.putExtra("stacktrace", s);
myContext.startActivity(intent);
//for restarting the Activity
Process.killProcess(Process.myPid());
System.exit(0);
}}
In your application or in every activity class, inside the onCreate() method then simply call:
For Kotlin'ers, call these two extension extension functions inside your MainActivity's onCreate() method, right after the super call and preferably before any other code you'd normally write inside onCreate().
fun Activity.handleUncaughtException() {
Thread.setDefaultUncaughtExceptionHandler { _, throwable ->
// here you can report the throwable exception to Sentry or Crashlytics or whatever crash reporting service you're using, otherwise you may set the throwable variable to _ if it'll remain unused
val intent = Intent(this, MainActivity::class.java).apply {
putExtra("isCrashed", true)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
}
startActivity(intent)
finish()
Process.killProcess(Process.myPid())
exitProcess(2)
}
}
fun Activity.showUncaughtExceptionDialog() {
if (intent.getBooleanExtra("isCrashed", false)) {
AlertDialog.Builder(this).apply {
setTitle("Something went wrong.")
setMessage("Something went wrong.\nWe'll work on fixing it.")
setPositiveButton("OK") { _, _ -> }
}.show()
}
}
We call Process.killProcess(Process.myPid()) and exitProcess(2) because if we look at the Android's open-source code, that's actually the default and proper handling that gets called by Thread. getDefaultUncaughtExceptionHandler(), it's what causes our applications to crash and the infamous ANR dialog brought up, and we want to be good Android citizens by following the original implementation rather than doing anything funky at the end of uncaughtException(), like not crashing at all or displaying another activity (never do this).
Note that Kotlin's exitProcess() method is just a wrapper around Java's System.exit(), whatever status code you pass in the constructor doesn't matter, I set it to 2 in my code.
Notice that in the intent we put a boolean flag "isCrashed" set to true, we'll use this to detect whether an unexpected exception caused the app to restart, and display a dialog to the user accordingly to inform them about the crash.
The showUncaughtExceptionDialog() extension function is optional, but if you're going to restart the app due to a crash, it's good manners to inform the user about it.