Android O对应用在后台运行时可以执行的操作施加了限制,称为后台执行限制(Background Execution Limits),这可以大大减少应用的内存使用和耗电量,提高用户体验。后台执行限制分为两个部分:后台服务限制(Background Service Limitations)、广播限制(BroadcastLimitations)。
后台服务限制
如何才算是后台应用?除了下面情况外都是后台应用
1. 具有可见的Activity
2. 具有前台服务
3. 另一个前台应用已关联到该应用(通过bindService或者使用该应用的ContentProvider)。
当应用处于后台时:
1.在后台运行的服务在几分钟内会被stop掉(模拟器测试在1分钟左右后被kill掉)。在这段时间内,应用仍可以创建和使用服务。
2.在应用处于后台几分钟后(模拟器测试1分钟左右),应用将不能再通过startService创建后台服务,如果创建则抛出以下异常
Caused by: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.example.samsung.test/.TestService }: app is in background
应用处于后台时,虽然不能通过startService创建后台服务,但仍可以通过下面的方式创建前台服务。
NotificationManager noti = (NotificationManager)getApplicationContext().getSystemService(NOTIFICATION_SERVICE);noti.startServiceInForeground();
后台服务会被kill掉,官方推荐可使用AlarmManager、SyncAdapter、JobScheduler代替后台服务。
广播限制
如果应用监听一些系统广播,当系统发出广播时,很多应用都会被唤醒,这会导致所有应用快速地连续消耗资源,从而降低用户体验。其实,大部分应用都不会处理这个广播,应用只是唤醒一下看看和自己是否有关,为了缓解这一问题,Android N对一些广播做出了限制:
1.targetSdkVersion为Android N(API level 24)及以上的应用,如果应用在AndroidManifest.xml中静态注册CONNECTIVITY_ACTION这个receiver,应用将不能收到此广播。如果应用使用Context.registerReceiver()动态注册receiver,应用仍可以收到这个广播。
2.运行在Android N及以上设备的应用,无论是targetSdkVersion是否是Android N,应用都不能发送或者接收ACTION_NEW_PICTURE和ACTION_NEW_VIDEO这两个广播。
而Android O执行了更为严格的限制。
1.动态注册的receiver,可接收任何显式和隐式广播。
2.targetSdkVersion为Android O(API level 26)及以上的应用,静态注册的receiver将不能收到隐式广播,但可以收到显式广播。下面例子说明
清单文件的receiver声明
android:name=".TestReceiver"
android:enabled="true">
android:name="com.test.example.testreceiver.action">
Receiver类定义
public class TestReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "onReceive", Toast.LENGTH_SHORT).show();
}
}
①如果这样发送隐式广播,receiver将接收不到广播。
Intent intent = new Intent();
intent.setAction("com.test.example.testreceiver.action");
sendBroadcast(intent);
②如果这样发送显式广播,receiver仍可以接收到广播
Intent intent = new Intent();
intent.setClassName("com.test.example.testreceiver","com.test.example.testreceiver.TestReceiver");
sendBroadcast(intent);
虽然静态注册的receiver不能接收隐式广播,但Google考虑到一些广播也不频繁发生,也有一些例外,对这些例外的静态注册的receiver,仍可接收隐式和显式广播。
ACTION_LOCKED_BOOT_COMPLETED、ACTION_BOOT_COMPLETED
ACTION_USER_INITIALIZE
ACTION_TIMEZONE_CHANGED
ACTION_LOCALE_CHANGED
ACTION_USB_ACCESSORY_ATTACHED
ACTION_USB_ACCESSORY_DETACHED
ACTION_USB_DEVICE_ATTACHED
ACTION_USB_DEVICE_DETACHED
ACTION_HEADSET_PLUG
……
详情请参考
https://developer.android.com/preview/features/background-broadcasts.html
据Google工程师透露,Google的目标是充满一次电,手机可用2~3天,这也可看到Google在手机续航方面的努力。
目前只有Android Studio2.4可以下载Android O 预览版SDK,下载地址
https://dl.google.com/dl/android/studio/ide-zips/2.4.0.6/android-studio-ide-171.3934896-windows.zip
Android 8.0新特性-取消大部分静态注册广播
今天楼主在写一个广播的demo,功能非常的简单,就是一个应用发送一个自定义的广播,同时在这个应用里面定义了一个广播接受者,并且在AndroidManifest文件中进行静态的注册。Demo看上去非常的简单,但是在Android 8.0的设备运行这个应用,始终不能接收到这个发送出去的广播,感觉非常的蒙蔽。关键是,在Android 7.0的设备是能够接收到的!
1.原因
看到这个情况,我就觉得不是我的代码问题,应该是Android 8.0相较于Android 8.0之前的设备有所变换,于是Google了一把,果然被我找到了问题所在。在Google爸爸的Android官网找到了Android 8.0行为变更的介绍,其中有一句说的是:
这句话的意思就是说,在Android 8.0的平台上,应用不能对大部分的广播进行静态注册,也就是说,不能在AndroidManifest文件对有些广播进行静态注册,这里必须强调是有些广播,因为有些广播还是能够注册的。比如,经过楼主测试,对接收Android 开机的广播通过静态注册还是能够正常接收的。
Android 8.0行为变更的介绍链接:https://developer.android.com/about/versions/oreo/android-8.0-changes.html?hl=zh-cn,前面那个链接必须通过FQ,当然我们提倡科学上网,所以国内镜像网站链接:https://developer.android.google.cn/about/versions/oreo/android-8.0.html。
2.解决办法
前面我们知道了是什么原因导致的,只要知道了原因,解决办法就非常容易的想出来的。
我们知道广播的注册方式分为两种:
A.静态注册,也就是说在AndroidManifest文件中对BroadcastReceiver进行注册,通常还会加上action用来过滤。
B.动态注册,调用Context中的registerReceiver对广播进行动态注册,使用unRegisterReceiver方法对广播进行取消注册的操作。
静态注册不行的话,那我们就动态注册啊!
3.代码
MainActivity文件的代码
public class MainActivity extends AppCompatActivity {
private Button mButton = null;
private IntentFilter mIntentFilter = null;
private MyBroadcastReceiver mMyBroadcastRecvier = null;
@Override 11 protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//过滤器
mIntentFilter = new IntentFilter("pby");
//创建广播接收者的对象
mMyBroadcastRecvier = new MyBroadcastReceiver();
//注册广播接收者的对象
registerReceiver(mMyBroadcastRecvier, mIntentFilter); 21 mButton = (Button) findViewById(R.id.id_button);
mButton.setOnClickListener(new View.OnClickListener(){
@Override 24 public void onClick(View v) {
Intent intent = new Intent("pby");
//发送一个广播
sendBroadcast(intent);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
//取消广播接收者的注册
unregisterReceiver(mMyBroadcastRecvier);
}
}
MyBroadcastReceiver文件的代码
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "收到了自定义的广播", Toast.LENGTH_LONG).show();
}
}
只有上面的简单配置,没有修改AndroidManifest文件中任何的代码