ANR 事件后重启应用程序的问题
Problem with restarting the app, after an ANR event
我已经使用此 GitHub 存储库在我的应用程序中实现了 ANR 看门狗。看门狗监视 UI 线程,如果它被阻塞超过 10 秒,则重新启动应用程序。我的问题是它重新启动了应用程序两次,因此打乱了我所有的逻辑。
这是我对 WatchDog 的实现:
public class ANRWatchdog extends Thread {
private final Handler uiHandler = new Handler(Looper.getMainLooper());
private int count = 0; //
private static final int DEFAULT_WAIT_TIME = 10000; // in milliseconds
private volatile boolean anr = false;
private Context context;
public ANRWatchdog(Context context) {
super();
this.context = context;
}
private final Runnable counter = () -> count = (count + 1) % Integer.MAX_VALUE;
@Override
public void run() {
setName("WatchDog");
int lastCount;
while (!isInterrupted()) {
if ( anr){
anr = false;
return;
}
lastCount = count;
uiHandler.post(counter);
try {
Thread.sleep(DEFAULT_WAIT_TIME);
} catch (InterruptedException e) {
Log.e("WatchDog",
"Error while making the ANR thread sleep" + e);
return;
}
if (count == lastCount) {// means the value hasn't been incremented. UI thread has been blocked
anr = true;
Log.d("WatchDog", "Count hasn't incremented. This means ANR. Will restart the app. Thread Id : " +
android.os.Process.getThreadPriority(android.os.Process.myTid()));
uiHandler.removeCallbacks(counter, null);
uiHandler.removeCallbacksAndMessages(null);
ANRSharedPrefs.storeANR(context, true, SystemClock.elapsedRealtime());
ANRError error = ANRError.NewMainOnly();
Log.e("WatchDog", "" + error);
Log.d("WatchDog", "Now restarting the app");
RestartAppUtil.restartApp(context);
return;
}
}
}
}
看门狗是这样启动的
public class FileLogger extends Application {
ANRWatchDog watchDog = new ANRWatchDog(this);
/**
* Called when the application is starting, before any activity, service, or receiver objects (excluding content providers) have been created.
*/
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "Now launching Android Application : " + BuildConfig.VERSION_NAME);
File logFile = new File(ExternalStoragePath.getExternalCardPath(getApplicationContext()), "log.txt");
try {
String cmd = "logcat -v time -f " + logFile.getPath() + " TAG1:I TAG2:D TAG3:E *:S";
Runtime.getRuntime().exec(cmd);
} catch (IOException e) {
Log.e(TAG, "Exception during writing to log " + e);
}
watchDog.start();
}
}
这是我重新启动应用程序的方式,即 RestartUtil
public static void restartApp(Context context){
context.stopService(new Intent(context, Service.class));
Intent mStartActivity = new Intent(context, MainActivity.class);
mStartActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
mStartActivity.putExtra(KeyConstants.ANR, true);
int mPendingIntentId = 123456;
PendingIntent mPendingIntent = PendingIntent.getActivity(context, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
Runtime.getRuntime().exit(0);
}
此代码有效,应用程序已重新启动。
我正在使用无限 while 循环模拟其中一项活动中的 ANR。当我这样做时,这就是日志中发生的事情
10-17 13:30:08.221 19588-19608/com.company.project D/TAG1 Count hasn't incremented. This means ANR. Will restart the app. Thread Id : 0
10-17 13:30:08.221 19588-19608/com.company.project D/TAG1 Storing the ANR time : 617417608
10-17 13:30:08.231 19588-19608/com.company.project D/TAG1 Now restarting the app
10-17 13:30:18.411 20333-20353/com.company.project D/TAG1 Count hasn't incremented. This means ANR. Will restart the app. Thread Id : 0
10-17 13:30:18.411 20333-20353/com.company.project D/TAG1 Storing the ANR time : 617427797
10-17 13:30:18.421 20333-20353/com.company.project D/TAG1 Now restarting the app
10-17 13:30:18.791 20362-20362/? D/TAG1: Getting the value of ANR time 617427797
10-17 13:30:18.791 20362-20362/? D/TAG1: Received intent in main screen
10-17 13:30:20.171 20362-20362/com.company.project D/TAG1 Getting the value of ANR time
10-17 13:30:20.171 20362-20362/com.company.project D/TAG1 Received intent in main screen 617427797
主要 activity 收到两个意图,而不是一个。我也不明白
的存在
/? D/TAG1
在日志中
谁能帮我弄清楚为什么主屏幕有两个意图?
所以我终于能够解决这个问题。
System.exit() 对我来说还不够。我不得不在导致 ANR 的 activity 上调用 finish() 或 finishAffinity()。
所以在
onCreate()
每个活动的方法,我像这样在 FileLogger 中注册 activity 的实例
FileLogger.setActivityName(this);
这是 FileLogger 的修改方式
/**to register the activity)
public static void setActivityName(Activity activityName){
anrActivity = activityName;
}
/**This method is called by RestartUtil method to restart the app**/
public static void kill(){
if ( anrActivity != null) {
anrActivity.finish();
anrActivity.finishAffinity();
}
android.os.Process.killProcess(android.os.Process.myPid());
}
我已经使用此 GitHub 存储库在我的应用程序中实现了 ANR 看门狗。看门狗监视 UI 线程,如果它被阻塞超过 10 秒,则重新启动应用程序。我的问题是它重新启动了应用程序两次,因此打乱了我所有的逻辑。
这是我对 WatchDog 的实现:
public class ANRWatchdog extends Thread {
private final Handler uiHandler = new Handler(Looper.getMainLooper());
private int count = 0; //
private static final int DEFAULT_WAIT_TIME = 10000; // in milliseconds
private volatile boolean anr = false;
private Context context;
public ANRWatchdog(Context context) {
super();
this.context = context;
}
private final Runnable counter = () -> count = (count + 1) % Integer.MAX_VALUE;
@Override
public void run() {
setName("WatchDog");
int lastCount;
while (!isInterrupted()) {
if ( anr){
anr = false;
return;
}
lastCount = count;
uiHandler.post(counter);
try {
Thread.sleep(DEFAULT_WAIT_TIME);
} catch (InterruptedException e) {
Log.e("WatchDog",
"Error while making the ANR thread sleep" + e);
return;
}
if (count == lastCount) {// means the value hasn't been incremented. UI thread has been blocked
anr = true;
Log.d("WatchDog", "Count hasn't incremented. This means ANR. Will restart the app. Thread Id : " +
android.os.Process.getThreadPriority(android.os.Process.myTid()));
uiHandler.removeCallbacks(counter, null);
uiHandler.removeCallbacksAndMessages(null);
ANRSharedPrefs.storeANR(context, true, SystemClock.elapsedRealtime());
ANRError error = ANRError.NewMainOnly();
Log.e("WatchDog", "" + error);
Log.d("WatchDog", "Now restarting the app");
RestartAppUtil.restartApp(context);
return;
}
}
}
}
看门狗是这样启动的
public class FileLogger extends Application {
ANRWatchDog watchDog = new ANRWatchDog(this);
/**
* Called when the application is starting, before any activity, service, or receiver objects (excluding content providers) have been created.
*/
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "Now launching Android Application : " + BuildConfig.VERSION_NAME);
File logFile = new File(ExternalStoragePath.getExternalCardPath(getApplicationContext()), "log.txt");
try {
String cmd = "logcat -v time -f " + logFile.getPath() + " TAG1:I TAG2:D TAG3:E *:S";
Runtime.getRuntime().exec(cmd);
} catch (IOException e) {
Log.e(TAG, "Exception during writing to log " + e);
}
watchDog.start();
}
}
这是我重新启动应用程序的方式,即 RestartUtil
public static void restartApp(Context context){
context.stopService(new Intent(context, Service.class));
Intent mStartActivity = new Intent(context, MainActivity.class);
mStartActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
mStartActivity.putExtra(KeyConstants.ANR, true);
int mPendingIntentId = 123456;
PendingIntent mPendingIntent = PendingIntent.getActivity(context, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
Runtime.getRuntime().exit(0);
}
此代码有效,应用程序已重新启动。
我正在使用无限 while 循环模拟其中一项活动中的 ANR。当我这样做时,这就是日志中发生的事情
10-17 13:30:08.221 19588-19608/com.company.project D/TAG1 Count hasn't incremented. This means ANR. Will restart the app. Thread Id : 0
10-17 13:30:08.221 19588-19608/com.company.project D/TAG1 Storing the ANR time : 617417608
10-17 13:30:08.231 19588-19608/com.company.project D/TAG1 Now restarting the app
10-17 13:30:18.411 20333-20353/com.company.project D/TAG1 Count hasn't incremented. This means ANR. Will restart the app. Thread Id : 0
10-17 13:30:18.411 20333-20353/com.company.project D/TAG1 Storing the ANR time : 617427797
10-17 13:30:18.421 20333-20353/com.company.project D/TAG1 Now restarting the app
10-17 13:30:18.791 20362-20362/? D/TAG1: Getting the value of ANR time 617427797
10-17 13:30:18.791 20362-20362/? D/TAG1: Received intent in main screen
10-17 13:30:20.171 20362-20362/com.company.project D/TAG1 Getting the value of ANR time
10-17 13:30:20.171 20362-20362/com.company.project D/TAG1 Received intent in main screen 617427797
主要 activity 收到两个意图,而不是一个。我也不明白
的存在/? D/TAG1
在日志中
谁能帮我弄清楚为什么主屏幕有两个意图?
所以我终于能够解决这个问题。
System.exit() 对我来说还不够。我不得不在导致 ANR 的 activity 上调用 finish() 或 finishAffinity()。
所以在
onCreate()
每个活动的方法,我像这样在 FileLogger 中注册 activity 的实例
FileLogger.setActivityName(this);
这是 FileLogger 的修改方式
/**to register the activity)
public static void setActivityName(Activity activityName){
anrActivity = activityName;
}
/**This method is called by RestartUtil method to restart the app**/
public static void kill(){
if ( anrActivity != null) {
anrActivity.finish();
anrActivity.finishAffinity();
}
android.os.Process.killProcess(android.os.Process.myPid());
}