Android保活方案
1:low memory killer
系统出于性能和体验上的考虑,APP退到后台后并不会真正的kill、掉进程,而是将其缓存起来。
打开的应用越多,缓存的应用也就越多,在系统进程不足的情况下,系统根据自己的一套进程回收机制,来判断kill掉哪些进程,以腾出进程给需要的app,这套进程回收机制叫做low memory killer。
2:内存不足
内存阀值,每个手机都不一样,当可用内存小于该值得时候,Android就会杀死对应优先级得进程。
3:进程的优先级
进程的优先级通过oom_adj来判断,oom_adj取值如下:
adj级别 | 值 | 说明 |
---|---|---|
UNKNOWN_ADJ | 16 | 预留的最低级别,一般对于缓存的进程才有可能设置成这个级别 |
CACHED_APP_MAX_ADJ | 15 | 缓存进程,空进程,在内存不足的情况下就会优先被kill |
CACHED_APP_MIN_ADJ | 9 | 缓存进程,也就是空进程 |
SERVICE_B_ADJ | 8 | 不活跃的进程 |
PREVIOUS_APP_ADJ | 7 | 切换进程 |
HOME_APP_ADJ | 6 | 与Home交互的进程 |
SERVICE_ADJ | 5 | 有Service的进程 |
HEAVY_WEIGHT_APP_ADJ | 4 | 高权重进程 |
BACKUP_APP_ADJ | 3 | 正在备份的进程 |
PERCEPTIBLE_APP_ADJ | 2 | 可感知的进程,比如那种播放音乐 |
VISIBLE_APP_ADJ | 1 | 可见进程 |
FOREGROUND_APP_ADJ | 0 | 前台进程 |
PERSISTENT_SERVICE_ADJ | -11 | 重要进程 |
PERSISTENT_PROC_ADJ | -12 | 核心进程 |
SYSTEM_ADJ | -16 | 系统进程 |
NATIVE_ADJ | -17 | 系统起的Native进程 |
0-3是比较安全的oom_adj一般不会被系统杀死的,所以我们只要保证自己的app oom_adj在0-3之间就可以了。
可以通过adb命令:cat /proc /4181/oom_adj来查看自己app的oom_adj的值
4181是进程号
保活
方案1:activity1像素保活
原理:手机关闭屏幕的时候,偷偷创建一个activity,让应用成为前台进程,打开屏幕时关闭activity,这样用户就不会发现什么异常,我们知道前台应用的oom_adj为0是不会被杀死的,这样就达到看保活的目的。
//设置1像素
Window window = getWindow();
window.setGravity(Gravity.LEFT | Gravity.TOP);
WindowManager.LayoutParams params = window.getAttributes();
params.x = 0;
params.y = 0;
params.height = 1;
params.width = 1;
window.setAttributes(params);
缺点:activity不够干净,只有在息屏的时候才生效,存在局限性比较大,而且谷歌原生的系统息屏的时候不会清理进程,但是现在很多厂商会在息屏的时候清理内存,所以本方案的可行性不高,可以作为了解。
方案2:前台service保活
保活原理:启动一个前台服务,从而拉高整个应用的优先级。
因为一旦通知被用户干掉那么该保活方案就不好用了,所以通知图标存在与否是该方案是否可行的关键。
但是该方案是谷歌官方承认的保活方案,所以可行性还是很高的。
需要适配
API<18通知图标不会显示
//activity中
startservice(new Intent( packagecontext: this, Foregroundservice. class)):
//service中
startforeground(1, new Notification());
API>=18&&API<26可以启动双服务,绑定同样的D,然后stop
这个方法的原理是8.0系统之前会根据服务的id来判断通知,那么第二个id设置跟第一个相同,然后自杀,系统就会误认为此通知已死就不会通知了,那么通知栏上面就不会显示
//activity中
startservice(new Intent( packagecontext: this, Foregroundservice. class)):
//service中
startforeground(1, new Notification());
public static class Innerservice extends Service {
@Nullable
@Override
public Ibinder onbind(Intent intent){
return null;
}
@Override
public void oncreate() {
super.oncreate
startforeground(1, new Notification())
stopself();
}
API>=26后暂时没有方式能够隐藏
8.0之后不可以创建同样的id的通知,所以此隐藏通知的方法就不好用了,当然了,通知显示与否不是该方案成功的评判标准,所以说还是可以用的。
拉活
1:广播拉活
1.1:系统广播拉活
在发生特定系统事件时,系统会发出广播,通过在 Androidmanifest中静
态注册对应的广播监听器,即可在发生响应事件时拉活
但是从 android7.0开始,对广播进行了限制,而且在8.0更加严格该方法就不适用了。
1.2:全家桶拉活
有多个app在用户设备上安装,只要开启其中一个就可以将其他的app也拉
活。比如手机里装了手Q、QQ空间、兴趣部落等等,那么打开任意一个app后,其
他的app也都会被唤醒
2:账户(account)同步拉活
系统每隔一段时间会进行账户同步,当系统去账户同步的时候(不一定多长时间,跟系统有关),我们就去拉活app,这个方案是非常稳定的,当然了国内的系统都是定制的,所以还是需要一定的适配的。
优点:系统唤醒,比较稳定
缺点:时间不能把控
2.1注册一个service,添加一个系统可识别的action
<service android: name- account. Authenticationservice
<intent-filter>
<action android: name-androld. accounts. Accountauthenticator
</intent-filter
<meta-data
android: name="android, accounts, Accountauthenticato
android: resource="@xml/account authenticator /
</service>
2.2service中通过binder把AccountAuthenticator 对象告诉系统
private AccountAuthenticator accountAuthenticator;
@override
public IBinder on Bind(Intent intent) {
return account Authenticator.getIBinder() ;
@override
public void onCreate() {
super.onCreate() ;
accountAuthenticator=new AccountAuthenticator(context:this) ;
2.3:同步账户:
public class Syncservice extends service{
private SyncAdapter mSyncAdapter;
private static final String TAG="SyncService";
@override
public IBinder onBind(Intent intent) {
return mSyncAdapter.getSyncAdapterBinder() ;
@override
public void onCreate() {
super.onCreate() ;
mSyncAdapter=new SyncAdapter(getApplicationContext() , true) ;
public static class SyncAdapter extends AbstractThreadedSyncAdapter{
public SyncAdapter(Context context, boolean auto Initialize) {
super(context, autoInitialize) ;
@override
public void onPerformSync(Accounta ccount, Bundle extras, String authority, ContentProvider clientprovider, SyncResult syncResult{
Log.e(TAG, “同步账户") ;
//与互联网或者本地数据库同步账户
}
2.4:添加权限
<uses-permission
android:name="android.permission.AUTHENTICATE_ACCOUNTS"
android:maxsdkversion="22"/>
<uses-permission
android:name="android.permission, GET_ACCOUNTS"
android:maxsdkversion="22"/>
<uses-permissionandroid:name="android.permission.MRITE_SYNC_SETTINGS"/>
3:JobScheduler拉活
JobScheduler允许在特定状态与特定时间间隔周期执行任务。可以利
用它的这个特点完成保活的功能,效果即开启一个定时器,与普通定时器不
同的是其调度由系统完成。
同样在某些ROM可能并不能达到需要的效果
@Requires Api(api=Build.VERSION.CODES.LOLLIPOP
public class MyJob service extends Jobservice{
public static void startJob(Context context) {
JobScheduler jobscheduler=(Jobscheduler) context.getSystemservice(Context.JOB_SCHEDULER_SERVICE) ;
JobInfo.Builder builder=new JobInfo.Builder(8, new ComponentName(context.get PackageName() ,
HyJob service.class.getName() ) ) .setPersisted(true) ;
//小于7.0
builder.setPeriodic(1000) ;//6.0以后最小是5s
//大于7.0
builder. set MinimumLatency(1000) ;//6.0以后最小是5s
job scheduler.schedule(builder.build() ) ;
}
@override
public boolean onStartJob(JobParameters params) {
//大于7.0
startJob(this);
return false;
}
@override
public boolean onStopJob(Jobparameters params) {
return false;
}
}