Android 进程保活

在系统内存不足的情况下,系统会依据自身的一套进程回收机制来回收掉一些进程,以腾出内存来供给需要的app,这套进程回收机制就叫做Low Memory Killer。然而某些应用需要在后台常驻以满足一些需求,比如后台接收推送消息等。那么如何保持进程常驻呢,总结了如下方案:

1.利用Android前台Service的漏洞,之前看Tinker源码发现也是使用这种方式。

具体步骤:对于Api < 18,调用startForeground(id , new Notification()),开启一个空的Notification,再通知栏不会显示。
对于Api > 18,在需要提高优先级的Service中启动一个InnerService,两个服务同时调用startForeground,并且使用同一个id。然后stop掉InnerService。

代码如下:


public class KeepLiveService extends Service {
 
    public static final int NOTIFICATION_ID=100;
 
    public KeepLiveService() {
    }
 
    @Override
    public IBinder onBind(Intent intent) {
    }
 
    @Override
    public void onCreate() {
        super.onCreate();
         //API 18以下,直接发送Notification并将其置为前台
        if (Build.VERSION.SDK_INT <Build.VERSION_CODES.JELLY_BEAN_MR2) {
            startForeground(NOTIFICATION_ID, new Notification());
        } else {
            //API 18以上,发送Notification并将其置为前台后,启动InnerService
            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;
        }
        @Override
        public void onCreate() {
            super.onCreate();
            //发送与KeepLiveService中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);
 
        }
    }
}

2.开启一像素的Activity,据说这是手Q的进程保活方案。该方案的思路是在锁屏时候开启一个大小为1像素的Activity,并且透明无切换动画,在开屏时关掉这个Activity,由于是透明无切换动画,所以能不让用户察觉。

代码如下:

public class SinglePixelActivity extends Activity {
 
    public static final String TAG = SinglePixelActivity.class.getSimpleName();
 
    public static void actionToSinglePixelActivity(Context pContext) {
        Intent intent = new Intent(pContext, SinglePixelActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        pContext.startActivity(intent);
    }
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_singlepixel);
        Window window = getWindow();
        //放在左上角
        window.setGravity(Gravity.START | Gravity.TOP);
        WindowManager.LayoutParams attributes = window.getAttributes();
        //宽高设计为1个像素
        attributes.width = 1;
        attributes.height = 1;
        //起始坐标
        attributes.x = 0;
        attributes.y = 0;
        window.setAttributes(attributes);
        ScreenManager.getInstance(this).setActivity(this);
    }
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}


public class ScreenManager {
 
    private Context mContext;
 
    private WeakReference<Activity> mActivityWref;
 
    public static ScreenManager gDefualt;
 
    public static ScreenManager getInstance(Context pContext) {
        if (gDefualt == null) {
            gDefualt = new ScreenManager(pContext.getApplicationContext());
        }
        return gDefualt;
    }
    private ScreenManager(Context pContext) {
        this.mContext = pContext;
    }
 
    public void setActivity(Activity pActivity) {
        mActivityWref = new WeakReference<Activity>(pActivity);
    }
 
    public void startActivity() {
            SinglePixelActivity.actionToSinglePixelActivity(mContext);
    }
 
    public void finishActivity() {
        //结束掉SinglePixelActivity
        if (mActivityWref != null) {
            Activity activity = mActivityWref.get();
            if (activity != null) {
                activity.finish();
            }
        }
    }
}

3.双进程互相守护

同时开启两个Service,分别是A和B,互相守护,如果B挂掉了,A就立刻把B启动起来,所以A和B互相守护,无论谁被杀掉,对方就把它拉起来。具体方式是通过bindServie方式来互相绑定对方,分别在不同的进程中避免同时被杀死。

首先定义两个Service,分别是LocalService和RemoteService,其中RemoteService需要配置android:process= ":remote"属性,代码如下:

 public class LocalService extends Service {

    private MyBinder mBinder;    
    private PendingIntent mPintent;    
    private MyServiceConnection mServiceConnection;

    @Override    
    public void onCreate() {        
    super.onCreate();        
    if (mBinder == null) {
       mBinder = new MyBinder();
     }
       mServiceConnection = new MyServiceConnection();
    }

    @Override  
    public int onStartCommand(Intent intent, int flags, int startId) {
        bindService(new Intent(this, RemoteService.class), myServiceConnection, Context.BIND_IMPORTANT);
        Notification notification = new Notification(R.drawable.ic_launcher, "", System.currentTimeMillis());
        mPintent = PendingIntent.getService(this, 0, intent, 0);
        notification.setLatestEventInfo(this, "", "自启", pintent);

        startForeground(startId, notification);        
        return START_STICKY;
    }    

 class MyServiceConnection implements ServiceConnection {

        @Override        
        public void onServiceConnected(ComponentName arg0, IBinder arg1) {

        }

        @Override        
        public void onServiceDisconnected(ComponentName arg0) {            
            // 连接出现了异常断开了,被杀掉了
            Toast.makeText(LocalService.this, "远程服务Remote被干掉", Toast.LENGTH_LONG).show();
            startService(new Intent(LocalService.this, RemoteService.class));
            bindService(new Intent(LocalService.this, RemoteService.class),
                    mServiceConnection, Context.BIND_IMPORTANT);
        }

    } 
       
 class MyBinder extends Connection.Stub {

        @Override        
        public String getProName() throws RemoteException {            
           return "";
        }

    }

    @Override    
    public IBinder onBind(Intent arg0) {        
       return mBinder;
    }
}

public class RemoteService extends Service {
    private  MyBinder mBinder;    
    private PendingIntent mPintent;    
    private MyServiceConnection mServiceConnection;

    @Override    
    public void onCreate() {       
     super.onCreate();        
     if (myBinder == null) {
            mBinder = new MyBinder();
        }
        mServiceConnection = new MyServiceConnection();
    }

    @Override    
    public int onStartCommand(Intent intent, int flags, int startId) {        
        this.bindService(new Intent(this,LocalService.class), mServiceConnection, Context.BIND_IMPORTANT);
        Notification notification = new Notification(R.drawable.ic_launcher,"",System.currentTimeMillis());
        mPintent=PendingIntent.getService(this, 0, intent, 0);
        notification.setLatestEventInfo(this, "", "防止被杀掉!", pintent);
        startForeground(startId, notification);        
        return START_STICKY;
    }    
    
class MyServiceConnection implements ServiceConnection {

        @Override        
        public void onServiceConnected(ComponentName arg0, IBinder arg1) {

        }

        @Override        
        public void onServiceDisconnected(ComponentName arg0) {
            Toast.makeText(RemoteCastielService.this, "本地服务Local被干掉", Toast.LENGTH_LONG).show();
            startService(new Intent(RemoteService.this,LocalService.class));
            bindService(new Intent(RemoteService.this,LocalService.class), mServiceConnection, Context.BIND_IMPORTANT);
        }

    }    
    
class MyBinder extends Connection.Stub {

        @Override       
        public String getProName() throws RemoteException {            
           return "";
        }

    }

    @Override    
    public IBinder onBind(Intent arg0) {        
       return mBinder;
    }
}

除了上面几种方式,进程保活还有JobSheduler和后台播放无声音频等方式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值