天天看點

學徒淺析Android——Android 8.0(O)背景服務的限制和變化

      Android 最近幾版的特色主要集中在省電和背景管理上,O的釋出,對Service和Broadcast又近一步加強了管束。主要可概括為如下兩點:

      1、背景應用不被允許建立背景服務,必須通過JobScheduler或者Context.startForegroundService()進行建立

      2、特定的隐式廣播不再被允許啟動,必須通過JobScheduler調用或者顯式注冊的方式才能啟動

      google之是以限制隐式廣播,是因為廣播的濫用導緻裝置在息屏等狀态下,依然無法有效的做到省電,往往一個系統廣播,會喚醒多個未啟動的第三方應用。是以在O中,隐式廣播的限制是很嚴厲的。谷歌給出了允許隐式注冊的廣播清單https://developer.android.com/preview/features/background-broadcasts.html,為了友善懶得上牆的小夥伴們,貼出整理的廣播清單:

開機廣播,之是以被允許,因為每次裝置啟動隻會發送一次
1、ACTION_LOCKED_BOOT_COMPLETED(直接啟動模式下才會發出)
2、ACTION_BOOT_COMPLETED

以下三個廣播有權限限制,一般應用無法接受。
3、ACTION_USER_INITIALIZE
4、android.intent.action.USER_ADDED
5、android.intent.action.USER_REMOVED

地區變更廣播,這個地區指的是國家一級,一般不會發送
6、ACTION_LOCALE_CHANGED
7、
時區鬧鐘變更相關的廣播,一般時間類APP需要
7、ACTION_TIMEZONE_CHANGED
8、ACTION_NEXT_ALARM_CLOCK_CHANGED
9、android.intent.action.TIME_SET

usb事件廣播,需要裝置觸發usb事件才能發送
10、ACTION_USB_ACCESSORY_ATTACHED
11、ACTION_USB_ACCESSORY_DETACHED
12、ACTION_USB_DEVICE_ATTACHED
13、ACTION_USB_DEVICE_DETACHED

藍牙事件廣播,需要裝置觸發藍牙事件才能發送
14、ACTION_CONNECTION_STATE_CHANGED
15、ACTION_ACL_CONNECTED
16、ACTION_ACL_DISCONNECTED

OEM相關的廣播,一般是OEM通訊類應用會需要
17、ACTION_CARRIER_CONFIG_CHANGED
18、TelephoneyIntents.ACTION_*_SUBSCRIPTION_CHANGED
19、TelephoneyIntents.SECRET_CODE_ACTION

登入使用者狀态發生改變時,這裡指的是google登入,一般我們用不到,同時這個廣播也在API26中廢棄了。
20、LOGIN_ACCOUNTS_CHANGED_ACTION

使用者通過設定頁面清除掉應用資料後才會發出
21、ACTION_PACKAGE_DATA_CLEARED

來電廣播
22、ACTION_NEW_OUTGOING_CALL

裝置隐私狀态變更廣播
23、ACTION_DEVICE_OWNER_CHANGED

月曆提醒廣播,是由月曆提供者發送給月曆程式的
24、ACTION_EVENT_REMINDER

程式解除安裝廣播,跟程式解除安裝相關的廣播中隻有這個是被允許的。
25、ACTION_PACKAGE_FULLY_REMOVED

裝置媒體相關廣播,但是一般會在開機時發出或者是在實體裝置互動時發出。
26、ACTION_MEDIA_MOUNTED
27、ACTION_MEDIA_UNMOUNTABLE
28、ACTION_MEDIA_CHECKING
29、ACTION_MEDIA_UNMOUNTED
30、ACTION_MEDIA_EJECT
31、ACTION_MEDIA_REMOVED
32、ACTION_MEDIA_BAD_REMOVAL

短信接收廣播
33、SMS_RECEIVED_ACTION
34、WAP_PUSH_RECEIVED_ACTION
           

    可以概括的說,可以進行隐式注冊的廣播都是非頻繁發送的,或者有着特定的觸發場景的。google的目的就是杜絕一個廣播喚醒多個背景應用這種現象。如果我們的應用中涉及到了清單以外的廣播,就有必要進行O的适配了。

    google針對前台應用的定義,認為如果滿足以下任意條件,應用将被視為處于前台:

1、具有可見 Activity(不管該 Activity 已啟動還是已暫停)。

   2、具有前台服務。

   3、另一個前台應用已關聯到該應用(不管是通過綁定到其中一個服務,還是通過使用其中一個内容提供程式)。
           

  但在開發中,我們會更多的遇到背景運作的需求,當應用處于背景時,監聽特定的系統廣播或者設定守護Service顯然不能很好的适應高版本,是以按照google的劇本走才是正道。以上兩各變更點都提到了JobScheduler,JobScheduler作為API21新增類,如它的名字計劃任務一樣,通過設定限制條件,使系統可以在不影響使用者體驗的情況下安排這些作業執行。應用作業不會主動擠占系統運作時間,而是在限制範圍下執行工作。Android也在不斷地增加JobScheduler支援的限制條件,Oreo就新增了一個運作場景:

       1、NETWORK_TYPE_METERED 作業需要一個按流量計費的網絡連接配接,比如大多數移動資料網絡資料套餐。

新增了兩個限制條件:

      1、JobInfo.isRequireStorageNotLow() 如果裝置的可用存儲空間非常低,作業将不會運作。

      2、JobInfo.isRequireBatteryNotLow() 如果電池電量等于或低于臨界門檻值,作業将不會運作;臨界門檻值是指裝置顯示 Low battery warning系統對話框的電量。

  當你需要持續的背景監聽功能時,用守護Service或者監聽特定的高頻系統廣播顯然已經不合時宜了,google希望你通過JobSchedular來實作類似的功能。JobScheduler的運作實質是JobService,google對JobService的定義有這樣一句話:This service executes each incoming job on a {@link android.os.Handler} running on your application's main thread.表明JobService是在主線程處理任務,也就是說當一個JobService處于onStartJob()時,應用程序實際是處于激活狀态的,滿足上文前台定義中的第二條:具有前台服務。而任務處理又是在系統許可範圍内,可謂是皆大歡喜。同時JobService是繼承自Service的,它的生命周期是:

onCreated()-->onStartJob-->onStopJob()-->jobFinished()-->onDestroy()
           

onCreated()繼承自Service,google對onCreated的定義是這樣的:Called by the system when the service is first created.  Do not call this method directly.即目前服務被建立時會調用一次,被建立意味着這個服務之前沒有存在過或者被onDestroy了。

onStartJob()-->onStopJob()這個工作階段取決于配置的限制條件,onStartJob()不會無限制的重複執行。如果我們不設定限制條件,那麼JobService在建立成功後隻會調用一次onStartJob。onDestroy()同樣繼承自Service的,google對onDestroy的定義有這樣一句話:Called by the system to notify a Service that it is no longer used and is being removed.即當系統想要回收目前服務時,便會觸發onDestroy,至于間隔多久會觸發取決于系統目前操作。我們可以在onDestroy()中重新執行一次建立操作,即重新通知系統安排一次計劃任務。保證我們的JobScheduler始終存在于系統任務排程隊列中了,這樣任務就會持續的運作下去,具體操作如下:

    (1)建立一個JobService命名為DetectionService,在onCreated()中顯式注冊一個BroadcastReceiver,用來接收應用自身的廣播或者其他系統廣播,作為喚醒JobService的輔助方式。(畢竟還有安全軟體這種東西的存在)

@Override
    public void onCreate() {
        super.onCreate();
        receiver = new AuxiliaryReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("your app's broadcasts");
        intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
        registerReceiver(receiver, intentFilter);
    }
           

(2)在onDestroy()中執行重新建立目前JobService操作,不設定限制條件。

@Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
        JobScheduler scheduler = null;
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
            scheduler = this.getSystemService(JobScheduler.class);
        }else{
            scheduler = (JobScheduler) this.getSystemService(Context.JOB_SCHEDULER_SERVICE);
        }
        final JobInfo.Builder builder = new JobInfo.Builder(1024,new ComponentName(this, DetectionService.class));
        builder.setPersisted(true);
        builder.setOverrideDeadline(1000);
        scheduler.schedule(builder.build());
    }
           

(3)在onStartJob()中,你可以根據自己的需求安排具體操作。

  這種設計方式,可以實作類似Service常駐背景的效果,同時符合Android O中對背景運作的要求,但是會對省電模式有影響,如果你的APP沒有這方面的顧慮話可以采取這種方式,如果有省電相關的需求,那就老老實實的隻用JobScheduler啟動一次。google通過JobScheduler規範背景應用啟動的目的,就是為了保證裝置的正常休眠和應用功耗的可控,我們在開發過程中更多的去遵守google标準,才能讓使用者有更好的産品體驗。

繼續閱讀