[崩溃] Android应用自动重启
背景
在App开发过程中,我们经常需要自动重启的功能。比如:
- 登录或登出的时候,为了清除缓存的一些变量,比较简单的方法就是重新启动app。
- crash的时候,可以捕获到异常,直接自动重启应用。
- 在一些debug的场景中,比如设置了一些测试的标记位,需要重启才能生效,此时可以用自动重启,方便测试。
那我们如何实现自动重启的功能呢?我们都知道如何杀掉进程,但是当我们的进程被杀掉之后,如何唤醒呢?
这篇文章就来和大家介绍一下,实现应用自动重启的几种方法。
方法1 AlarmManager
private void setAlarmManager(){
Intent intent = new Intent();
intent.setClass(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, System.currentTimeMillis()+100, pendingIntent);
Process.killProcess(Process.myPid());
System.exit(0);
}
使用AlarmManager实现自动重启的核心思想:创建一个100ms之后的Alarm任务,等Alarm任务到执行时间了,会自动唤醒App。
缺点:
- 在App被杀和拉起之间,会显示系统
Launcher桌面,体验不好。 - 在高版本不适用
方法2 直接启动Activity
private void restartApp(){
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Process.killProcess(Process.myPid());
System.exit(0);
}
缺点:
- MainActivity必须是Standard模式
方法3 ProcessPhoenix
JakeWharton大神开源了一个叫ProcessPhoenix的库,这个库可以实现无缝重启app。
实现原理其实很简单,我们先讲怎么使用,然后再来分析源码。
使用方法
首先引入ProcessPhoenix库,这个库不需要初始化,可以直接使用。
implementation 'com.jakewharton:process-phoenix:2.1.2'
使用1:如果想重启app后进入首页:
ProcessPhoenix.triggerRebirth(context);
使用2:如果想重启app后进入特定的页面,则需要构造具体页面的intent,当做参数传入:
Intent nextIntent = //...
ProcessPhoenix.triggerRebirth(context, nextIntent);
有一点需要特别注意。
- 我们通常会在
Application的onCreate方法中做一系列初始化的操作。 - 如果使用
Phoenix库,需要在onCreate方法中判断,如果当前进程是Phoenix进程,则直接return,跳过初始化的操作。
if (ProcessPhoenix.isPhoenixProcess(this)) {
return;
}
源码
ProcessPhoenix的原理:
- 当调用
triggerRebirth方法的时候,会启动一个透明的Activity,这个Activity运行在:phoenix进程 Activity启动后,杀掉主进程,然后用:phoenix进程拉起主进程的Activity- 关闭当前
Activity,杀掉:phoenix进程
先来看看Manifest中Activity的注册代码:
<activity
android:name=".ProcessPhoenix"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:process=":phoenix"
android:exported="false"
/>
可以看到这个Activity确实是在:phoenix进程启动的,且是Translucent透明的。
整个ProcessPhoenix的代码只有不到120行,非常简单。我们来看下triggerRebirth做了什么。
public static void triggerRebirth(Context context) {
triggerRebirth(context, getRestartIntent(context));
}
不带intent的triggerRebirth,最后也会调用到带intent的triggerRebirth方法。
getRestartIntent会获取主进程的Launch Activity。
private static Intent getRestartIntent(Context context) {
String packageName = context.getPackageName();
Intent defaultIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
if (defaultIntent != null) {
return defaultIntent;
}
}
所以要调用不带intent的triggerRebirth,必须在当前App的manifest里,指定Launch Activity,否则会抛出异常。
接着来看看真正的triggerRebirth方法:
public static void triggerRebirth(Context context, Intent... nextIntents) {
if (nextIntents.length < 1) {
throw new IllegalArgumentException("intents cannot be empty");
}
// 第一个activity添加new_task标记,重新开启一个新的stack
nextIntents[0].addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
Intent intent = new Intent(context, ProcessPhoenix.class);
// 这里是为了防止传入的context非Activity
intent.addFlags(FLAG_ACTIVITY_NEW_TASK); // In case we are called with non-Activity context.
// 将待启动的intent作为参数,intent是parcelable的
intent.putParcelableArrayListExtra(KEY_RESTART_INTENTS, new ArrayList<>(Arrays.asList(nextIntents)));
// 将主进程的pid作为参数
intent.putExtra(KEY_MAIN_PROCESS_PID, Process.myPid());
// 启动ProcessPhoenix Activity
context.startActivity(intent);
}
triggerRebirth方法,主要的功能是启动ProcessPhoenix Activity,相当于启动了:phoenix进程。同时,会将nextIntents和主进程的pid作为参数,传给新启动的ProcessPhoenix Activity。
下面我们再来看看,ProcessPhoenix Activity的onCreate方法,看看新进程启动后做了什么。
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 首先杀死主进程
Process.killProcess(getIntent().getIntExtra(KEY_MAIN_PROCESS_PID, -1)); // Kill original main process
ArrayList<Intent> intents = getIntent().getParcelableArrayListExtra(KEY_RESTART_INTENTS);
// 再启动主进程的intents
startActivities(intents.toArray(new Intent[intents.size()]));
// 关闭当前Activity,杀掉当前进程
finish();
Runtime.getRuntime().exit(0); // Kill kill kill!
}
:phoenix进程主要做了以下事情:
- 杀死主进程
- 用传入的
Intent启动主进程的Activity(也可以是Service) - 关闭
phoenix Activity,杀掉phoenix进程
总结
如果App有自动重启的需求,比较推荐使用ProcessPhoenix的方法。
原理其实非常简单:
- 启动一个新的进程
- 杀掉主进程
- 用新的进程,重新拉起主进程
- 杀掉新的进程
我们可以直接在工程里引入ProcessPhoenix开源库,也可以自己用代码实现这样的机
来源:juejin.cn/post/7207743145999024165