有些时候(国内通常是这样)我们需要应用在 后台存活,但是现在的很多手机room是在内存不足或者一定时间后销毁进程的。
总结几种android常用的保活手段。
系统出于体验和性能上的考虑,app在退到后台时系统并不会真正的kill掉这个进程,而是将其缓存起来。打开的应用越多,后台缓存的进程也越多。在系统内存不足的情况下,系统开始依据自身的一套进程回收机制来判断要kill掉哪些进程,以腾出内存来供给需要的app, 这套杀进程回收内存的机制就叫 Low Memory Killer。
cat /sys/module/lowmemorykiller/parameters/minfree //查看内存阈值
进程的优先级通过进程的adj值来反映,它是linux内核分配给每个系统进程的一个值,进程回收机制根据这个值来决定是否进行回收。adj的值越小,进程的优先级越高。
cat /proc/32393/oom_adj 查看进程的adj值
一,提升进程优先级
1)Activity提权
监听应用退入后台以后就启动一个透明的1px大小的activity
2)Service提权
创建一个前台服务用于提高app在按下home键之后的进程优先级startForeground(ID,Notification):
API level < 18 :参数2 设置 new Notification(),图标不会显示。
API level >= 18:在需要提优先级的service A启动一个InnerService。两个服务都startForeground,且绑定同样的 ID。Stop 掉InnerService ,通知栏图标被移除。
3)广播拉活
在发生特定系统事件时,系统会发出广播,通过在 AndroidManifest 中静态注册对应的广播监听器,即可在发生响应事件时拉活。
但是从android 7.0开始,对广播进行了限制,而且在8.0更加严格
4)账户同步 拉活
手机系统设置里会有“帐户”一项功能,任何第三方APP都可以通过此功能将数据在一定时间内同步到服务器中去。系统在将APP帐户同步时,会将未启动的APP进程拉活。(过程过于麻烦,而且不能控制重启时间)
5)JobScheduler 拉活
JobScheduler允许在特定状态与特定时间间隔周期执行任务。可以利用它的这个特点完成保活的功能,效果即开启一个定时器,与普通定时器不同的是其调度由系统完成。
同样在某些ROM可能并不能达到需要的效果(某米)
public static void StartJob(Context context) {
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context
.JOB_SCHEDULER_SERVICE);
// setPersisted 在设备重启依然执行
JobInfo.Builder builder = new JobInfo.Builder(10, new ComponentName(context
.getPackageName(), MyJobService.class
.getName())).setPersisted(true);
//小于7.0
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
// 每隔1s 执行一次 job
builder.setPeriodic(1_000);
} else {
//延迟执行任务
builder.setMinimumLatency(1_000);
}
jobScheduler.schedule(builder.build());
}
private static final String TAG = "MyJobService";
@Override
public boolean onStartJob(JobParameters params) {
Log.e(TAG, "开启job");
//如果7.0以上 轮训
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
StartJob(this);
}
return false;
}
不能保证适配所有机型
6)双进程守护
这个是目前来说最靠谱的了,但是也不是一定可以(有些可以一键清理后台进程的)。
class ServiceConnection implements android.content.ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//服务连接后回调
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG,"主进程可能被干掉了,拉活");
//连接中断后回调
startService(new Intent(RemoteService.this, LocalService.class));
bindService(new Intent(RemoteService.this, LocalService.class), serviceConnection,
BIND_AUTO_CREATE);
}
}
另外还有native fork进程监听主进程的,这个5.0之前还行,之后就废了。