Android:Service?;?/h2>

1: 開(kāi)啟一個(gè)像素的Activity
系統(tǒng)一般是不會(huì)殺死前臺(tái)進(jìn)程的。所以要使得進(jìn)程常駐,我們只需要在鎖屏的時(shí)候在本進(jìn)程開(kāi)啟一個(gè)Activity,
為了欺騙用戶(hù),讓這個(gè)Activity的大小是1像素,并且透明無(wú)切換動(dòng)畫(huà),
在開(kāi)屏幕的時(shí)候,把這個(gè)Activity關(guān)閉掉,所以這個(gè)就需要監(jiān)聽(tīng)系統(tǒng)鎖屏廣播.

//權(quán)限
    <uses-permission android:name="android.permission.RECEIVE_USER_PRESENT"/>

//注冊(cè)
    <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();
            //寬高設(shè)計(jì)為1個(gè)像素
            attributes.width = 1;
            attributes.height = 1;
            //起始坐標(biāo)
            attributes.x = 0;
            attributes.y = 0;
            window.setAttributes(attributes);

            ScreenManager.getInstance(this).setActivity(this);
        }

        @Override
        protected void onDestroy() {
            super.onDestroy();
        }
    }


    在屏幕關(guān)閉的時(shí)候把SinglePixelActivity啟動(dòng)起來(lái),
    在開(kāi)屏的時(shí)候把SinglePixelActivity 關(guān)閉掉,
    所以要監(jiān)聽(tīng)系統(tǒng)鎖屏廣播,以接口的形式通知MainActivity啟動(dòng)或者關(guān)閉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狀態(tài)廣播接收者
         */
        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)) { // 開(kāi)屏
                    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管理類(lèi)
    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() {
            //結(jié)束掉SinglePixelActivity
            if (mActivityWref != null) {
                Activity activity = mActivityWref.get();
                if (activity != null) {
                    activity.finish();
                }
            }
        }
    }
    
    現(xiàn)在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進(jìn)程是否存在,如果存在的話(huà),
    就利用startActivities啟動(dòng)MainActivity和DetailActivity。
    為什么還要啟動(dòng)MainActivity而不直接只啟動(dòng)DetailActivity?
    因?yàn)橛腥缦虑闆r,進(jìn)程中的所有Activity都已經(jīng)退出了,但進(jìn)程還沒(méi)有被系統(tǒng)回收,
    這時(shí)判斷進(jìn)程是否存在返回true,然后只啟動(dòng)DetailActivity的話(huà),按Back鍵任務(wù)棧就直接到底,返回桌面了。
    而我們要的效果是按Back鍵返回上一級(jí)Activity,也就是MainActivity。

    如果app進(jìn)程已經(jīng)退出,不存在了,此時(shí)就用一個(gè)Intent啟動(dòng)應(yīng)用,
    該Intent中包含一個(gè)Bundle, Bundle中存有啟動(dòng)DetailActivity所需的參數(shù),
    這個(gè)Intent傳入SplashActivity后,再由SplashActivity傳給MainActivity,在MainActivity中加入判斷,
    如果有該參數(shù),則表示應(yīng)用是從通知欄啟動(dòng)的,要進(jìn)行跳轉(zhuǎn)到DetailActivity的操作,否則就是常規(guī)啟動(dòng)。
    
    (缺點(diǎn): 如果沒(méi)root 在部分機(jī)器上會(huì)造成廣播監(jiān)聽(tīng)不到)

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

START_STICKY
如果系統(tǒng)在onStartCommand返回后被銷(xiāo)毀,系統(tǒng)將會(huì)重新創(chuàng)建服務(wù)并依次調(diào)用onCreate和onStartCommand(
注意:根據(jù)測(cè)試Android2.3.3以下版本只會(huì)調(diào)用onCreate根本不會(huì)調(diào)用onStartCommand,
        Android4.0可以辦到),這種相當(dāng)于服務(wù)又重新啟動(dòng)恢復(fù)到之前的狀態(tài)了)。

3
JobSheduler
JobSheduler是作為進(jìn)程死后復(fù)活的一種手段,
native進(jìn)程方式最大缺點(diǎn)是費(fèi)電,
Native 進(jìn)程費(fèi)電的原因是感知主進(jìn)程是否存活有兩種實(shí)現(xiàn)方式,在 Native 進(jìn)程中通過(guò)死循環(huán)或定時(shí)器,輪訓(xùn)判斷主進(jìn)程是否存活,當(dāng)主進(jìn)程不存活時(shí)進(jìn)行拉活。
其次5.0以上系統(tǒng)不支持。
但是JobSheduler可以替代在Android5.0以上native進(jìn)程方式,這種方式即使用戶(hù)強(qiáng)制關(guān)閉,也能被拉起來(lái),親測(cè)可行。

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

注:服務(wù)保活的前提是:要盡可能減少內(nèi)存和電量的消耗。

Android 7.0版本以上,目前沒(méi)有什么真正意義上的?;?。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容