背景
在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
开源库,也能够自己用代码完成这样的机制,总归都比较简单。