android__進程保活最新適配

    “安卓手機爲什麼老是這麼卡”,

     “安卓手機高配置的低能兒”

作爲一個安卓開發工程師,不知道聽到別人這麼說安卓的時候,你怎麼感想。

之前遇到個問題,app在後臺殺死後,用戶進行暖啓動,用戶會直接進入之前瀏覽過的頁面。這時公共bean的數據是沒有的,但是每次後臺請求數據時,是需要各種請求頭的,這時就會出錯。當時,只有一年工作經驗的我第一想到的就是保活,而且當時覺得保活很帥,我想實戰一下。但是,在和師傅商量後,否定了自己的想法。最後,我們在父類activity中每次判斷公共bean中的一個字段是否爲空實現的。後來,我想想其實保活對這個問題起不了多大作用,而且浪費系統資源。所以思路,交流,理解需求很重要。

爲什麼需要保活? 我們需要做一些實時的事情。比如:IM, 及時推送。

進程想要常駐後臺,一般兩類方法:保活和拉活。

保活: 白名單,1像素,前臺服務保活

拉活: 賬戶同步拉活,JobScheduler,雙進程,workManager

 

1像素:手機鎖屏後,在屏幕上開一個1像素的界面,將app置爲前臺進程。因爲國內手機廠商爲了息屏後省電,會將部分後臺進程殺死。

 一像素Activity:

public class KeepAct extends Activity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //直接用windo設置該acitivty爲1像素
        Window window = getWindow();
        WindowManager.LayoutParams params = window.getAttributes();
        params.y = 0;
        params.x = 0;
        params.width = 1;
        params.height = 1;
        window.setAttributes(params);

        PowerManager powerManager = (PowerManager) this
                .getSystemService(Context.POWER_SERVICE);
        boolean ifOpen = powerManager.isScreenOn();
        if (ifOpen)
            finish();
        else
            KeepManager.getInstance().setmActivity(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e("KeepAct", "onResume");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e("KeepAct", "onDestroy");
    }
}

1像素控制類:

public class KeepManager {

    //惡漢單例
    private static KeepManager keepManager = new KeepManager();
    //全局---便於註銷
    private KeepRevice keepRevice;
    //弱引用KeepAct,釋放它
    private WeakReference mActivity;

    private KeepManager() {
    }

    public static KeepManager getInstance() {
        return keepManager;
    }

    /**
     * 註冊監聽 屏幕亮暗的廣播
     *
     * @param context
     */
    public void register(Context context) {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);

        keepRevice = new KeepRevice();
        context.registerReceiver(keepRevice, intentFilter);
    }

    /**
     * 註銷廣播
     *
     * @param context
     */
    public void unregister(Context context) {
        if (keepRevice != null)
            context.unregisterReceiver(keepRevice);
    }

    /**
     * 屏幕亮了
     */
    public void screenOn() {
        if (mActivity != null) {
            Activity activity = (Activity) mActivity.get();
            if (activity != null)
                activity.finish();
            mActivity = null;
        }
    }

    /**
     * 屏幕息屏
     */
    public void screenOff(Context context) {
        Intent intent = new Intent(context, KeepAct.class);
        context.startActivity(intent);
    }

    public void setmActivity(Activity mActivity) {
        this.mActivity = new WeakReference<Activity>(mActivity);
    }

}

設置廣播監聽:

public class KeepRevice extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        if (TextUtils.equals(intent.getAction(), Intent.ACTION_SCREEN_OFF)) {
            KeepManager.getInstance().screenOff(context);
        } else {
            KeepManager.getInstance().screenOn();
        }

    }

}

使用的時候,直接調用   KeepManager.getInstance().register(getApplication()); 不要忘記銷燬廣播。我們這裏需要注意的兩點:1.keepactivity 需要設置爲透明的,不然會閃爍一層黑色;2.keepactivity需要設置一個單獨的棧,否則會讓你的app莫名其妙開屏後跳出來,交互不好。

前臺服務保活:開啓一個前臺服務,提高應用的優先。

  4.3之前,開啓一個服務設置爲前臺進程即可;

  4.3開始,系統會通知用戶,有一個前臺進程服務,如微信視頻時候,通知欄中的通知。如果,不想讓用戶看到。8.0之前可以再啓動一個service,關閉通知消息,8.0之後則會強制顯示了。

如果通知不影響需求效果的話,這是一個不錯的保活方法。具體實現如下:

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
            //4.3以下,將service設置成前臺服務,並且不顯示通知消息
            startForeground(SERVICE_ID, new Notification());
        } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            //4.3-->7.0,將service設置成前臺服務
            startForeground(SERVICE_ID, new Notification());
            //刪除通知消息
            startService(new Intent(this, InnerService.class));
        } else {
            //8.0以上,通知欄消息需要設置channel
            NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            NotificationChannel channel = new NotificationChannel("channel", "xx", NotificationManager.IMPORTANCE_MIN);
            if (manager != null) {
                manager.createNotificationChannel(channel);
                Notification notification=new NotificationCompat.Builder(this,"channel").build();
                startForeground(SERVICE_ID,notification);
            }
        }

當然4.3到7.0的時候,可以自啓動一個service。關閉了通知,再自己銷燬。

 public static class InnerService extends Service {

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

        @Override
        public void onCreate() {
            super.onCreate();
            //讓服務變成前臺服務
            startForeground(SERVICE_ID, new Notification());
            //關閉自己
            stopSelf();
        }
    }

上面說的是儘量不讓我們的app被系統殺死。如果app不幸已經殺死了,需要拉活app。

賬戶同步拉活:系統提供給app一段時間與服務器同步數據的工具,不同的手機時間段不同,一般情況是15分鐘。但是,不是每個app都會被同步,需要添加自己的app。在設置中的其他賬戶(oppo中這麼設置,別的手機不一樣)可以查看正在賬戶同步的app。

第一張和第三張是已經同步的app,第二張是添加了賬戶的app,還沒有同步。實測中小米和華爲8.0的手機表現可以,其他的手機大家測試一下。這種適配方式適合一般的推送的需求。


小米6x
09-12 17:02:17.944 21270-25407/com.example.onepoition E/onPerformSync: 同步賬戶09/12  16:32
09-12 17:02:17.944 21270-25407/com.example.onepoition E/onPerformSync: 同步賬戶09/12  16:47
09-12 17:02:17.944 21270-25407/com.example.onepoition E/onPerformSync: 同步賬戶09/12  17:02
09-12 17:16:59.653 21270-25762/com.example.onepoition E/onPerformSync: 同步賬戶09/12  17:16

華爲AL_20:
09-12 17:02:17.944 21270-25407/com.example.onepoition E/onPerformSync: 同步賬戶09/12  16:38
09-12 17:02:17.944 21270-25407/com.example.onepoition E/onPerformSync: 同步賬戶09/12  16:54
09-12 17:08:05.750 16524-20199/com.example.onepoition E/onPerformSync: 同步賬戶09/12  17:08
09-12 17:22:10.139 16524-21152/com.example.onepoition E/onPerformSync: 同步賬戶09/12  17:22

JobScheduler:android 5.0給的api,可以在滿足特定條件下實現app的後臺進程,和賬戶同步拉活的功能和實現差不多。但是,國內好多產商對它做了很多不友好的操作。

 1.  在華爲和小米手機上,app手動殺死後無效了。同步賬戶可以仍同步;

 2.  很多廠商需要設置app自啓動權限;

 3.  有些手機一鍵清理,JobScheduler也會被清理。

雙進程:app開啓兩個進程,兩個進程各開一個服務,只要斷開連接,存活的進程把被殺死的進程拉活。雙進程拉活是一個比較老而且常用的方法。查看正在運行的app時,會發現有好多app是多進程機制。不過,現在很多多進程是因爲不同類型功能的分離。

 

總結:1. 首先考慮需求是否需要多進程,不要一直佔領後臺資源;

           2. 一個時間段的保活可以使用前臺服務保護。比如:微信視頻時,通知欄會有微信使用前臺服務通知;

           3. 不需要實時的推送可以使用賬戶同步 或者 JobScheduler,賬戶同步更優越些;

           4. 如果公司有能力,白名單一波,爽歪歪!!!

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