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

 

 

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章