Android--进程常驻--只说有用的

这个话题,网上很多,并且列出了一大堆,把各种可能猜测都搞了一遍,结果结论不明确,很多都是不了了之,我们要的是一个确实可以实现的方案,说那么多,到最后贴出来的代码很容易就被杀了,没用的,本文我只讲我觉得可以作为实际运用的方案,其他的就不多提了,最后会给出demo供大家验证。

 先说下现有的有哪些方案:

1、将Service设置为前台进程
2、在service的onStartCommand方法里返回 STATR_STICK
3、添加Manifest文件属性值为android:persistent=“true”
4、覆写Service的onDestroy方法
5、添加广播监听android.intent.action.USER_PRESENT事件以及其他一些可以允许的事件
6、服务互相绑定
7、设置闹钟,定时唤醒
8、账户同步,定时唤醒
9、开启一个1像素activity 前台保活
10、native进程

提前说明下,以下方案只对部分8.0以上手机有效,8.0以下基本都可以。

基本上就这些,当然还有些说是通过native 层的代码实现的,但是弊端很明显,跟厂商,和系统版本关系太大,而且还不靠谱。

基本分为两种方式来讲

  1.项目不需要在后台常驻进程,只是不要那么容易被系统回收

  2.后台需要有个进程常驻,长时间的去工作发现进程被杀后把他拉起来。

1.如果说只是要提高进程级别,当然进程oom_adj 值越小就越不容易被杀。我觉得上边的1、9就可以满足需求。但是前台进程会在8.0及以上状态栏留下一个通知,这个好像不太好,这个看需求,如果应用有通知类的东西或许会好点。

在讲之前先讲几个adb命令

adb shell ps 查看所有进程信息

adb shell "ps|grep 包名" 查看特定进程信息

adb shell "cat /proc/ppid号/oom_adj 查看进程优先级  8.0不可用了
adb shell am force-stop 包名   杀进程

1.非常驻进程

 1.开启一个1像素activity 前台保活,这个是能提高进程的优先级的

LiveService.java
public class LiveService extends Service {
    private static final String TAG = "LiveService";
    public static void toLiveService(Context pContext) {
        Intent intent = new Intent(pContext, LiveService.class);
        pContext.startService(intent);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate: ");
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand: ");
        final ScreenManager screenManager = ScreenManager.getInstance(LiveService.this);
        ScreenBroadcastListener listener = new ScreenBroadcastListener(this);
        listener.registerListener(new ScreenBroadcastListener.ScreenStateListener() {
            @Override
            public void onScreenOn() {
                Log.d(TAG, "onScreenOn: ");
                screenManager.finishActivity();
            }

            @Override
            public void onScreenOff() {
                Log.d(TAG, "onScreenOff: ");
                screenManager.startActivity();
            }
        });
        return START_REDELIVER_INTENT;
    }
}
ScreenBroadcastListener
public class ScreenBroadcastListener {
    Context mContext;
    ScreenBroadcastReceiver mScreenReceiver;
    ScreenStateListener mListener;

    public ScreenBroadcastListener(Context context) {
        mContext = context.getApplicationContext();
        mScreenReceiver = new ScreenBroadcastReceiver();

    }

    interface ScreenStateListener {
        void onScreenOn();

        void onScreenOff();
    }

    private class ScreenBroadcastReceiver extends BroadcastReceiver {
        String action = null;

        @Override
        public void onReceive(Context context, Intent intent) {
            action = intent.getAction();
            if (intent.ACTION_SCREEN_ON.equals(action)) {
                mListener.onScreenOn();
            } else if (intent.ACTION_SCREEN_OFF.equals(action)) {
                mListener.onScreenOff();
            }
        }
    }

    public void registerListener(ScreenStateListener listener) {
        mListener = listener;
        registerListener();
    }
    private  void registerListener(){
        IntentFilter filter=new IntentFilter();
        filter.addAction(Intent.ACTION_SCREEN_ON);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        mContext.registerReceiver(mScreenReceiver,filter);
    }
}
ScreenManager
public class ScreenManager {
    static ScreenManager gDefualt;
    WeakReference<Activity> mActivityWref;
    Context mContext;

    public ScreenManager(Context mContext) {
        this.mContext = mContext;
    }

    public static ScreenManager getInstance(Context context) {
        if (gDefualt==null) {
            gDefualt=new ScreenManager(context.getApplicationContext());
        }
        return gDefualt;
    }
    public void setActivity(Activity pActivity){
        mActivityWref = new WeakReference<>(pActivity);
    }
    public void startActivity(){
        LiveActivity.actionToLiveActivity(mContext);
    }
    public void finishActivity(){
        if (mActivityWref!=null) {
            Activity activity=mActivityWref.get();
            if (activity!=null) {
                activity.finish();
            }
        }
    }
}

 

2.开启前台服务用来提高优先级

KeepLiveService.java
public class KeepLiveService extends Service {
    public static final int NOTIFICATION_ID=0x11;

    public KeepLiveService() {

    }

    @Override
    public IBinder onBind(Intent intent) {
        return (IBinder) 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{
            //18以上
            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 class InnerService extends Service{

        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }

        @Override
        public void onCreate() {
            super.onCreate();
            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);
        }
    }
}

1.常驻进程

这个我尝试了很多种方式,觉得最靠谱的其实还是双进程守护,这里尝试了两种方式

1.应用内通过自身开启一个公有进程,注意了不是 “ :” 开头的,否则在手动杀进程时会被杀掉。

  

MyTestService.java
public class MyTestService extends Service {
    private static final String TAG = "MyTestService";
    int number=0;
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();


    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    number++;
                    Log.d(TAG, "run: "+number  );
                }
            }
        }).start();
        return super.onStartCommand(intent, flags, startId);

    }
}

AndroidManifest注册

<service android:name=".MyTestService"
    android:process="com.MyTestService">
    <intent-filter>
        <action android:name="android.liveservice.front"/>
    </intent-filter>
</service>

Activity 内启动服务进程,使用 adb shell ps 查看机器正在运行的进程

Intent intent = new Intent();
intent.setAction("android.liveservice.front");
intent.setPackage("com.example.servicelive1");
startService(intent);

这里我们看到有三个进程一个主进程,一个私有服务进程,一个公有服务进程,现在我们在设备上将应用进程杀掉。

三个进程全部被干掉了,因为我的设备是zuk  8.0的,再换成 小米pad2 5.1  也是全部被干掉了  换成nexus_5_25

竟然还活着。换成nexus_5_26 同样进程还活着,这说明我们的国产厂商对系统做了优化。

2.应用开启其他应用中的一个服务,用于对此应用进程进行守护。

nexus_5_26 首先安装一个应用服务公有(csdnactivity),启动自身应用(servicelive1)发现启动不了个了

Not allowed to start service Intent { act=android.liveservice pkg=com.example.csdnactivity }: app is in background uid null

直接告诉我不允许启动,因为被启动的服务所属的应用进程还未启动,用户不知道,没有相应的pid,看来8.0是真滴不行啊。

nexus_5_25 同理在这试下。

非常顺利,现在查看

u0_a84    31371 1371  1397788 48336 SyS_epoll_ 00000000 S com.example.servicelive1
u0_a83    31386 1371  1406656 47620 SyS_epoll_ 00000000 S com.example.csdnactivity

两个进程,其中一个就是另一个应用的进程了。

同理,杀进程。

u0_a83    31386 1371  1406656 47668 SyS_epoll_ 00000000 S com.example.csdnactivity

还在后台运行。此方法可行。仅限于8.0以下。

现在试下小米pad 5.1 的

首先保证两个应用都安装了,然后杀掉所有进程,然后启动 servicelive1 ,一切顺利,csdnactivity 服务被启动了,是一个后台服务,现在杀进程。

adb shell ps  看到有一个进程还在后台运行,现在设备上已经没有可杀进程了。

u0_a749   1211  2434  976340 45548 ffffffff 00000000 S com.example.csdnactivity

这样实现进程保活方案是可行的,通过那个后台进程,监听应用进程是否被杀,如果杀了,就把它拉起。但是没有找到一种万全的不被啥的方案,并且8.0以上不行。这里我只是简单讲了几种我觉得可以在项目中去使用的方案,还有其他一些尝试性的我都在demo中了。

如果你有更好的方案欢迎留言和吐槽。

 

 

进程常驻demo

 

 

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值