Android:Service保活

1: 開啟一個像素的Activity
系統一般是不會殺死前臺進程的。所以要使得進程常駐,我們只需要在鎖屏的時候在本進程開啟一個Activity,
為了欺騙用戶,讓這個Activity的大小是1像素,并且透明無切換動畫,
在開屏幕的時候,把這個Activity關閉掉,所以這個就需要監聽系統鎖屏廣播.

//權限
    <uses-permission android:name="android.permission.RECEIVE_USER_PRESENT"/>

//注冊
    <service android:name=".ui.service.MainService"
            android:process="1000"/>

    <receiver android:name=".ui.broadcastReceiver.ScreenBroadcastListener$ScreenBroadcastReceiver">
        <intent-filter android:priority="90000">
            <action android:name="android.intent.action.USER_PRESENT"/>
        </intent-filter>
    </receiver>

    
    
    
    
//1px Activity  
    public class SinglePixelActivity extends Activity {

        public static final String TAG = SinglePixelActivity.class.getSimpleName();

        
        
        public static void actionToSinglePixelActivity(Context context) {
            Intent intent = new Intent(context, SinglePixelActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent);
        }

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Log.d(TAG, "onCreate");
            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();
        }
    }


    在屏幕關閉的時候把SinglePixelActivity啟動起來,
    在開屏的時候把SinglePixelActivity 關閉掉,
    所以要監聽系統鎖屏廣播,以接口的形式通知MainActivity啟動或者關閉SinglePixActivity。
    public class ScreenBroadcastListener {

        private Context mContext;

        private ScreenBroadcastReceiver mScreenReceiver;

        private ScreenStateListener mListener;

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

        interface ScreenStateListener {

            void onScreenOn();

            void onScreenOff();
        }

        /**
         * screen狀態廣播接收者
         */
        private class ScreenBroadcastReceiver extends BroadcastReceiver {
            private 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);
        }
    }


    //1px Activity管理類
    public class ScreenManager {

        private Context mContext;

        private WeakReference<Activity> mActivityWref;

        public static ScreenManager gDefualt;

        public static ScreenManager getInstance(Context context) {
            if (gDefualt == null) {
                gDefualt = new ScreenManager(context.getApplicationContext());
            }
            return gDefualt;
        }
        private ScreenManager(Context context) {
            this.mContext = context;
        }

        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();
                }
            }
        }
    }
    
    現在MainActivity改成如下
    public class MainActivity extends AppCompatActivity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            final ScreenManager screenManager = ScreenManager.getInstance(MainActivity.this);
            ScreenBroadcastListener listener = new ScreenBroadcastListener(this);
             listener.registerListener(new ScreenBroadcastListener.ScreenStateListener() {
                @Override
                public void onScreenOn() {
                    screenManager.finishActivity();
                }

                @Override
                public void onScreenOff() {
                    screenManager.startActivity();
                }
            });
        }
    }

    初步的思路是先判斷app進程是否存在,如果存在的話,
    就利用startActivities啟動MainActivity和DetailActivity。
    為什么還要啟動MainActivity而不直接只啟動DetailActivity?
    因為有如下情況,進程中的所有Activity都已經退出了,但進程還沒有被系統回收,
    這時判斷進程是否存在返回true,然后只啟動DetailActivity的話,按Back鍵任務棧就直接到底,返回桌面了。
    而我們要的效果是按Back鍵返回上一級Activity,也就是MainActivity。

    如果app進程已經退出,不存在了,此時就用一個Intent啟動應用,
    該Intent中包含一個Bundle, Bundle中存有啟動DetailActivity所需的參數,
    這個Intent傳入SplashActivity后,再由SplashActivity傳給MainActivity,在MainActivity中加入判斷,
    如果有該參數,則表示應用是從通知欄啟動的,要進行跳轉到DetailActivity的操作,否則就是常規啟動。
    
    (缺點: 如果沒root 在部分機器上會造成廣播監聽不到)

2
系統自帶的,onStartCommand方法必須具有一個整形的返回值,
這個整形的返回值用來告訴系統在服務啟動完畢后,
如果被Kill,系統將如何操作,這種方案雖然可以,
但是在某些情況or某些定制ROM上可能失效,
認為可以多做一種保保守方案。

START_STICKY
如果系統在onStartCommand返回后被銷毀,系統將會重新創建服務并依次調用onCreate和onStartCommand(
注意:根據測試Android2.3.3以下版本只會調用onCreate根本不會調用onStartCommand,
        Android4.0可以辦到),這種相當于服務又重新啟動恢復到之前的狀態了)。

3
JobSheduler
JobSheduler是作為進程死后復活的一種手段,
native進程方式最大缺點是費電,
Native 進程費電的原因是感知主進程是否存活有兩種實現方式,在 Native 進程中通過死循環或定時器,輪訓判斷主進程是否存活,當主進程不存活時進行拉活。
其次5.0以上系統不支持。
但是JobSheduler可以替代在Android5.0以上native進程方式,這種方式即使用戶強制關閉,也能被拉起來,親測可行。

4 進程相互喚醒
  顧名思義,就是指的不同進程,
不同app之間互相喚醒,如你手機里裝了支付寶、淘寶、天貓、UC等阿里系的app,
那么你打開任意一個阿里系的app后,有可能就順便把其他阿里系的app給喚醒了。

注:服務保活的前提是:要盡可能減少內存和電量的消耗。

Android 7.0版本以上,目前沒有什么真正意義上的保活。
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容