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标准,才能让用户有更好的产品体验。
JobScheduler应用场景
当你需要在Android设备满足某种场合才需要去执行处理数据,例如
* 应用具有您可以推迟的非面向用户的工作(定期数据库数据更新)
* 应用具有当插入设备时您希望优先执行的工作(充电时才希望执行的工作备份数据)
* 需要访问网络或 Wi-Fi 连接的任务(如向服务器拉取内置数据)
* 希望作为一个批次定期运行的许多任务
而使用JobScheduler可以很优雅的完成这些情况。
所以相比于其他方式,JobScheduler的好处是显而易见的。
* 避免频繁的唤醒硬件模块,造成不必要的电量消耗。
* 避免在不合适的时间(例如低电量情况下、弱网络或者移动网络情况下的)执行过多的任务消耗电量;
JobScheduler和Android 6.0出现的Doze都一样,总结来说就是限制应用频繁唤醒硬件,从而达到省电的效果。
You do not instantiate this class