Android app主动杀死进程并重启
Posted herozqtc
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android app主动杀死进程并重启相关的知识,希望对你有一定的参考价值。
最近出现一个bug,这个bug还是很常见的很容易实现,在设计代码的时候还是需要注意的,就是在app授权location定位权限之后,将app放在后台,在设置里对app的权限关闭操作,再从后台打开app,app会crash。
这里的问题原因就是当settings里关闭了权限之后,安卓系统会主动关闭app进程,使得重新打开app时,之前保存的app的activity页面是被异常关闭的,会触发 onCreate方法的参数savedInstanceState: Bundle不为空。
同时之前内存中的累的对象不会保证数据的完整和正确被索引到,在我的例子里就是cache的对象被销毁了,重新打开app没有经过正常的初始化流程,导致crash。
搜集了资料发现,即使是微信也不可避免系统异常杀死当前process的行为,只能使用重启的操作重启app来规范这样的现象。
下面是总结的几个常用的app重启的方案:
/**
* 使用 AlarmManager 来帮助重启
*
* @param context
* @param cls
*/
public static void restartByAlarm(Context context, Class<?> cls)
Intent mStartActivity = new Intent(context, cls);
int mPendingIntentId = 123456;
PendingIntent pIntent = PendingIntent.getActivity(context, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + 500, pIntent);
System.exit(0);
/**
* 使用 killProcess 杀死自身,系统会恢复应用
*
* @param context
* @param cls
*/
public static void restartByKillProcess(Context context, Class<?> cls)
Intent intent = new Intent(context, cls);
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
android.os.Process.killProcess(android.os.Process.myPid());
/**
* 通过清栈触发应用重启。但不会重启 application ,与应用相关的静态变量也会更重启前一样。
*
* @param context
*/
public static void restartByClearTop(Context context)
Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);
/**
* 利用系统重启api触发应用重启
*
* @param context
*/
public static void restartBySystemApi(Context context)
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
manager.restartPackage(context.getPackageName());
/**
* 通过 Intent.makeRestartActivityTask 来触发应用重启,跟 restartByClearTop 类似。
* 但不会重启 application ,与应用相关的静态变量也会更重启前一样。
*
* @param context
*/
public static void restartByCompatApi(Context context, Class<?> cls)
Intent intent = new Intent(context, cls);
Intent restartIntent = Intent.makeRestartActivityTask(intent.getComponent());
context.startActivity(restartIntent);
System.exit(0);
/**
* 5.1 版本以后可以借助 JobScheduler 来重启应用
*
* @param context
*/
public static void restartByJobScheduler(Context context, Class<?> cls)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
int delayTimeMin = 1000;
int delayTimeMax = 2000;
MyJobSchedulerService.setMainIntent(new Intent(context, cls));
JobInfo.Builder jobInfoBuild = new JobInfo.Builder(0, new ComponentName(context, MyJobSchedulerService.class));
jobInfoBuild.setMinimumLatency(delayTimeMin);
jobInfoBuild.setOverrideDeadline(delayTimeMax);
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(jobInfoBuild.build());
System.exit(0);
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
static class MyJobSchedulerService extends JobService
private static Intent mIntent;
public static void setMainIntent(Intent intent)
mIntent = intent;
@Override
public boolean onStartJob(JobParameters params)
startActivity(mIntent);
jobFinished(params, false);
return false;
@Override
public boolean onStopJob(JobParameters params)
return false;
但是在使用第二种方案的时候,发现在加了判断savedInstanceState不为空的时候,重启之后savedInstanceState还是不为空,进入死循环。是因为单纯的重启app还是会保留上一次的页面的参数,就是之前系统异常杀死的时候的参数。
解决办法就是在重启之前调用一次finish()方法,只有这样,下次启动页面savedInstanceState的值就重置为null了。
最终kotlin的写法是:
if (savedInstanceState != null)
finish()
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
exitProcess(0)
但是这样还是有个问题,就是点击后台app重启,现象是会先杀掉,再重新打开app,会有个弹出的动画,给人一种启动两次的样子。
问题保留,以后深究。
systemd `systemctl stop` 主动杀死子进程
【中文标题】systemd `systemctl stop` 主动杀死子进程【英文标题】:systemd `systemctl stop` aggressively kills subprocesses 【发布时间】:2017-04-15 08:23:21 【问题描述】:我有一个类似守护进程的进程,它启动两个子进程(其中一个子进程启动约 10 个其他子进程)。当我systemctl stop
我的进程时,子子进程似乎被systemctl
'积极地'杀死 - 这并没有给我的进程清理的机会。
我如何让systemctl stop
退出积极的杀戮,从而让我的进程安排有序的清理?
我试过timeoutSec=30
无济于事。
【问题讨论】:
您查看过man systemd.services
和man systemd.kill
中的文档吗?
【参考方案1】:
KillMode=
[1] 默认为control-group
。这意味着您服务的每个进程都会被 SIGTERM 杀死。
你有两个选择:
在每个进程中处理 SIGTERM 并在TimeoutStopSec
内关闭(默认为 90 秒 [2])
如果你真的想从你的主进程中委托关闭,设置KillMode=mixed
。 SIGTERM 将仅发送到主进程。然后在TimeoutStopSec
内再次关机。如果您没有在TimeoutStopSec
内关闭,systemd 会将SIGKILL
发送到您的所有进程。
注意:我建议在选项 2 中使用 KillMode=mixed
而不是 KillMode=process
,因为后者只会将最终的 SIGKILL
发送到您的主进程,这意味着您的子进程不会被杀死锁起来了。
[1]https://www.freedesktop.org/software/systemd/man/systemd.kill.html#KillMode=
[2]https://www.freedesktop.org/software/systemd/man/systemd-system.conf.html#DefaultTimeoutStartSec=
【讨论】:
【参考方案2】:一个迟到的(可能的)答案,但是当我用谷歌搜索了几周的类似问题时,什么也没找到,我想我添加了我的解决方案。 我的错误是我以 root 身份运行 systemd 单元并(使用 sudo)切换到 startscript(继承自 SysVinit 脚本)中的“正确”用户。 这将启动 user.slice 中的进程,该进程在关机时被无情地杀死。当我将单元文件更改为以正确的用户 (USER=myuser) 身份运行并从启动脚本中删除 sudo 时,进程在 system.slice 中启动并在关机时得到正确处理。
【讨论】:
以上是关于Android app主动杀死进程并重启的主要内容,如果未能解决你的问题,请参考以下文章
我的 Android 小部件被杀死,“不再需要 bellander.andro ....”