Preface
In app development, it is inevitable that some unexpected problems will cause the app to crash. If the application cannot automatically restart, it will greatly affect the user experience. For example, the service of chat software that accepts messages in the background needs to always exist. If it cannot be restored in time after a crash, many messages will be missed. Another example is that ordinary weather applications need to obtain the weather regularly. If it cannot be restored in time after a crash, the user's understanding of the weather will lag, which may affect the user's travel.
In response to the above problems, improving the stability of the app is the most important, but we still need to save a hand to ensure that we can protect ourselves after the first layer of defense is breached.
Relevant knowledge supplement
There are two types of exceptions in Java: Checked exceptions and Unchecked exceptions. The former must use throws or try catch for exception handling, such as Thread.sleep()
file reading and writing; the latter does not need to be specified or captured, such as array out-of-bounds exceptions and null pointer exceptions.
Java's default handling of undetected exceptions is to write the stack trace information to the console (or log it to the error log file) and then exit the program.
When a thread is about to terminate due to an uncaught exception, the Java Virtual Machine will Thread.getUncaughtExceptionHandler()
query the thread using the method UncaughtExceptionHandler
and will call the handler's uncaughtException
method, passing the thread and exception as arguments.
If the thread has not explicitly set it UncaughtExceptionHandler
, its ThreadGroup
object will act as it UncaughtExceptionHandler
. If ThreadGroup
the object has no special requirements for handling exceptions, it can forward the call to the default uncaught exception handler.
accomplish
Based on the above principles, we can build a class, inherit the Java UncaughtExceptionHandler
interface, and override uncaughtException
the method to handle the crash problem and restart the application .
public class UnCeHandler implements Thread.UncaughtExceptionHandler {
private final Thread.UncaughtExceptionHandler mDefaultHandler;
Application application;
public UnCeHandler(Application application) {
//获取系统默认的UncaughtException处理器
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
this.application = application;
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
//....
}
}
In uncaughtException(Thread thread, Throwable ex)
, we can add custom exception handling
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
//如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
} else {
//设置定时重启
Intent intent = new Intent(application.getApplicationContext(), MainActivity.class);
PendingIntent restartIntent = PendingIntent.getActivity(
application.getApplicationContext(),
0,
intent,
PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr = (AlarmManager) application.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent);
//kill应用
android.os.Process.killProcess(android.os.Process.myPid());
}
}
It handleException(ex)
can be used to collect crash information and perform operations such as file storage or pop-up Toast.
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
//TODO:在此处处理捕获到的crash信息
return true;
}
The AlarmManager in the program is a timer in Android. By passing the PendingIntent object, the specified activity, service or broadcast can be started regularly, so that the app can be restarted regularly after being killed.
Note : For the crash restart of background services, 8.0 and above need to be woken PendingIntent.getForegroundService()
up. At the same time, the background service to be awakened must be started in the foreground.
PendingIntent restartIntent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
restartIntent = PendingIntent.getForegroundService(
application.getApplicationContext(), 0, intent, 0);
} else {
restartIntent = PendingIntent.getService(
application.getApplicationContext(), 0, intent, 0);
}
AlarmManager mgr = (AlarmManager) application.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent);
Finally, by setting a custom exception capture processor in the application, you can capture the exceptions of all threads globally.
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//程序崩溃时触发线程 以下用来捕获程序崩溃异常
Thread.setDefaultUncaughtExceptionHandler(new UnCeHandler(this));
}
}
Summarize
The idea of restarting an application after an abnormal crash is to Thread.UncaughtExceptionHandler
capture the exception of the app crash and then AlarmManager
reopen the application or background service by sending a scheduled broadcast.