进程保活的方式

  • 安卓杀死进程的一些机制
  • 保活的一些方式
  • 一像素保活法
  • 前台服务保活法


安卓杀死进程的一些机制

安卓中的进程主要分为以下五种:
1、前台进程
Foreground Process
2、可见进程
Visible Process
3、服务进程
Service Process
4、后台进程
Background Process
5、空进程
Empty Process

安卓的机制是在内存达到一定的阈值时就会杀死对应的等级进程。查看阈值的方法如下图(单位是4KB)。当然,这是在不同的定制系统上会有差异,手机厂商会修改该值。除了左数开始第五个之外,其他的都跟上面5个等级一一对应。如当内存小于 80640 * 4KB / 1024 = 315MB 时就会杀死空进程

Android 双守护进程保活缺点 安卓 进程守护_Android 双守护进程保活缺点

保活的一些方式

一像素保活法

原理就是监听屏幕的状态,当锁屏的时候,启动一个一像素的 activity 这样进程就会变成前台进程,锁屏时就不会被杀掉。屏幕开启时则关闭该Activity。

1、首先需要在MainActivity中注册一个监听手机屏幕状态的广播监听:

//注册监听屏幕的广播
mOnepxReceiver = new OnePixelReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.SCREEN_OFF");
intentFilter.addAction("android.intent.action.SCREEN_ON");
intentFilter.addAction("android.intent.action.USER_PRESENT");
registerReceiver(mOnepxReceiver, intentFilter);

2、监听到屏幕状态后的处理:

public class OnePixelReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
    if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {    //屏幕关闭启动1像素Activity
        Intent it = new Intent(context, OnePiexlActivity.class);
        it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(it);
    } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {   //屏幕打开 结束1像素
        context.sendBroadcast(new Intent("finish"));
        Intent main = new Intent(Intent.ACTION_MAIN);
        main.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        main.addCategory(Intent.CATEGORY_HOME);
        context.startActivity(main);
    }
}
}

启动模式要为 FLAG_ACTIVITY_NEW_TASK ,不然最进任务能看到整个进程被一个activity覆盖。
3、创建一像素activity

public class OnePiexlActivity extends Activity {

private BroadcastReceiver endReceiver;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //设置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);

    //结束该页面的广播
    endReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            finish();
        }
    };
    registerReceiver(endReceiver, new IntentFilter("finish"));
    //检查屏幕状态
    checkScreen();
}

@Override
protected void onResume() {
    super.onResume();
    checkScreen();
}

/**
 * 检查屏幕状态  isScreenOn为true  屏幕“亮”结束该Activity 
 */
private void checkScreen() {

    PowerManager pm = (PowerManager) OnePiexlActivity.this.getSystemService(Context.POWER_SERVICE);
    boolean isScreenOn = pm.isScreenOn();
    if (isScreenOn) {
        finish();
    }
}
}

同时要设置该activity为透明,不然又可能会被用户看见。

<style name="OnePixelActivity" parent="android:Theme.Holo.Light.NoActionBar">//无标题
    <item name="android:windowIsTranslucent">true</item>//透明
</style>
<activity
    android:name=".OnePiexlActivity"
    android:screenOrientation="portrait"
    android:excludeFromRecents="true"
    android:theme="@style/OnePixelActivity"/>

android:excludeFromRecents=“true” 设置该activity栈不显示在最近任务列表中。

听说该方法已经不可用了。至于为什么我也不太清楚。可能已经被谷歌在新版系统上优化了吧。
缺点:一定要关闭屏幕才能保活。如果用户持续使用手机长达数小时。进程可能已经在后台被杀掉了。

前台服务保活法

原理就是启动一个前台服务。但是启动前台服务会在通知栏显示一个无法消除的通知。
启动前台服务的方法很简单,只要在服务的 onCreate方法中 调用 startForeground(int,Notification).。

不同版本的api 通知栏显示不同:

API < 18 通知图标不会显示。
API >= 18 && API < 26 可以启动双服务,绑定同样的ID,然后stop一个服务,通知图标就自然不会显示了。
API >= 26 后暂时没有方式能隐藏通知

public class MyService extends Service {
    public static final int NOTIFICATION_ID=0x11;

    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        
        if (Build.VERSION.SDK_INT <Build.VERSION_CODES.JELLY_BEAN_MR2) {
            startForeground(NOTIFICATION_ID, new Notification());
        } else {
            
            Notification.Builder builder = new Notification.Builder(this);
            builder.setSmallIcon(R.mipmap.ic_launcher);
            startForeground(NOTIFICATION_ID, builder.build());
            startService(new Intent(this, InnerService.class));
        }
    }

    public  static class  InnerService extends Service{
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
        @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
        @Override
        public void onCreate() {
            super.onCreate();
            //发送与上面服务中ID相同的Notification,然后将其取消并取消自己的前台显示
            Notification.Builder builder = new Notification.Builder(this);
            builder.setSmallIcon(R.mipmap.ic_launcher);
            startForeground(NOTIFICATION_ID, builder.build());
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    stopForeground(true);
                    NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                    manager.cancel(NOTIFICATION_ID);
                    stopSelf();
                }
            },100);

        }
    }
}