[Android General] sylsau:
Hello,

I create that thread to present you a tutorial learning you how to Auto Restart an Android App after a Crash or a Force Close Error. You can also discover this tutorial and the demo video associated directly on Youtube :

[YOUTUBE]a8C-K4cDGpc[/YOUTUBE]

How to auto restart an Android Application after a Crash or a Force Close Error ?

The biggest nightmare of Android developers is the Crash or Force Close Error that can occur when a user uses one of their applications. Indeed, it’s always a bad message sent to the user and the major risk is that the user uninstalls the application. Unfortunately, you can’t always catch properly all errors and sometimes you can’t avoid a Crash or a Force Close Error. In these specific cases, a good approach is to configure auto restart for your Android Application. With this approach, you have better chances to keep users on your application.

To start, you need to create a custom Application class implementation to get an instance of your context continuously :

package com.ssaurel.appcrash;

import android.app.Application;
import android.content.Context;

public class MyApplication extends Application {

public static MyApplication instance;

@Override
public void onCreate() {
super.onCreate();
instance = this;
}

@Override
public Context getApplicationContext() {
return super.getApplicationContext();
}

public static MyApplication getInstance() {
return instance;
}
}

Don’t forget to add this Application implementation on your Android Manifest :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ssaurel.appcrash">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:name=".MyApplication">

<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>

To try the auto restart feature, we need to define a button in the layout of the Main Activity. When we will click on the button, we’re going to crash the application. The layout will have the following form :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.ssaurel.appcrash.MainActivity">

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Crash Me !"
android:onClick="crashMe"/>

</RelativeLayout>

Now, we enter in the core of our auto restart feature. You need to create a custom implementation of the UncaughtExceptionHandler interface. What is the purpose of this interface ? It’s an interface for handlers invoked when a Thread abruptly terminates due to an uncaught exception.

Our custom implementation will have the following form :

package com.ssaurel.appcrash;

import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;

public class MyExceptionHandler implements Thread.UncaughtExceptionHandler {

private Activity activity;

public MyExceptionHandler(Activity a) {
activity = a;
}

@Override
public void uncaughtException(Thread thread, Throwable ex) {
Intent intent = new Intent(activity, MainActivity.class);
intent.putExtra("crash", true);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_ACTIVITY_NEW_TASK);

PendingIntent pendingIntent = PendingIntent.getActivity(MyApplication.getInstance().getBaseContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT);

AlarmManager mgr = (AlarmManager) MyApplication.getInstance().getBaseContext().getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pendingIntent);

activity.finish();
System.exit(2);
}
}

When an uncaught exception occurs, the uncaughtException method will be called. We’re going to create an Intent to restart our application at the defined moment via an Alarm. Then, we finish the current activity and we exit the application. Note that we put a boolean parameter to indicate that the application is restarted.

Last step is to install the UncaughtExceptionHandler during the start of the application by calling the static setDefaultUncaughtExceptionHandler method of the Thread class :

package com.ssaurel.appcrash;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler(this));

if (getIntent().getBooleanExtra("crash", false)) {
Toast.makeText(this, "App restarted after crash", Toast.LENGTH_SHORT).show();
}
}

public void crashMe(View v) {
throw new NullPointerException();
}
}

Note that we launch a NullPointerException in the crashMe method to force the crash of the application and test the auto restart feature. Other thing to note is the crash boolean parameter test when the activity is launched. Like said previously, it lets us to know when the application is restarted after a crash or when the application is launched for the first time.

Now, you can launch the application and you should see the following screen after a click on the crashMe button :

Don't hesitate to give it a try and give me your feedbacks if you have some ideas for new tutorials.

Thanks.

Sylvain