在我看来,需要重点关注如下方面:
-
对Broadcast的限制
-
对后台Service的限制
从Android M以来,Android每个版本都为提升Android设备的电池续航做了不少努力,同时也为应用带来了越来越多的限制。
在Android O中,如果应用进入cached状态(即没有任何正在运行的component),系统将自动释放wakelock。
Android O不再允许background应用运行background service。
对于一个正在运行的应用,如果下列条件之一成立,那么该应用为foreground:
-
它有一个可见的Activity(不论是started状态还是paused状态)。
-
它有一个foreground service。
-
有其它foreground应用连接到它(不论是通过bind service还是访问content provider)。
如果上述条件都不满足,那么该应用为background。
当一个应用为foreground时,它可以自由地运行foreground service和background service。 在它转变为background时,它有一个几分钟的时间窗口,在此期间它依然可以运行service。 在那时间窗口之后,该应用将为idle状态。此时,系统会停掉该应用的background service。
当一个应用为background时,如果发生了某些特定事件(如,收到FCM高优先级消息、收到SMS/MMS broadcast、 执行Notification的PendingIntent等),该应用也会有一个几分钟的时间窗口,在此期间,它可以无限制地运行service。
💡
|
在OPP3版本中,测试结果表明,系统在等待1~1.5分钟后会stop background service。 |
💡
|
不论应用是foreground还是background状态,其它应用都可以正常地去bind该应用的bound service。 |
在Android O中,创建foreground service的方式也发生了变化:
-
由于Android O不允许background应用创建background service。因此 ,需要先调用Context#startForegroundService()来启动一个foreground service。
-
app需要在5秒内调用Service#startForeground()来展示用户可见的notification。 如果app没能在5秒内调用Service#startForeground(),系统将停掉该service,并把该应用置为ANR状态。
当我们调用
发送broadcast时,这个broadcast要么是explicit,要么是implicit。
如何判断呢?如果一个broadcast有明确的接收app,那么其就是explicit(例如,指定了component,或者指定了包名);
如果一个broadcast没有明确的接收app,那么它就是implicit。Context#sendBroadcast()
例如,
// case 1: explicit
Intent intent1 = new Intent(CommonConstants.ACTION_APP1_TEST_SELF);
intent1.setPackage(getPackageName());
context.sendBroadcast(intent1);
// case 2: explicit
Intent intent2 = new Intent();
intent2.setComponent(cn);
context.sendBroadcast(intent2);
// case 3: implicit
Intent intent3 = new Intent(CommonConstants.ACTION_APP1_TEST_NORMAL);
context.sendBroadcast(intent3);
// case 4: implicit with permission
Intent inten4 = new Intent(CommonConstants.ACTION_APP1_TEST_PERM_SIGN);
context.sendBroadcast(inten4, CommonConstants.PERM_SIGN);
在Android O中,对Broadcast新增了如下限制:
-
如果应用的target SDK为Android O或者以上版本,在AndroidManifest.xml中注册的 BroadcastReceiver将无法再接收到implicit broadcast。 有一个例外情况,如果此implicit broadcast是通过"signature"保护级别的权限发送的,且目标应用也有此权限, 那么在AndroidManifest.xml中注册的Broadcast依然可以接收到此broadcast。
没有变化的地方:
-
在AndroidManifest.xml中注册的BroadcastReceiver依然可以接收到explicit broadcast。
-
通过Context#registerReceiver()注册的BroadcastReceiver依然可以接收到所有broadcast。
-
如果app的target SDK为Android 8.0之前的版本,在AndroidManifest.xml中注册的BroadcastReceiver依然可以接收所有broadcast。
💡
|
见 AndroidOExplorer 中的测试代码。 |
💡
|
即使app的target SDK为Android O之前,用户也可以在Settings中app详情页面强制禁用app在后台运行。 |