一、前言

每次在后台运行时,应用都会消耗一部分有限的设备资源,例如 RAM。 这可能会影响用户体验,如果用户正在使用占用大量资源的应用(例如玩游戏或观看视频),影响会尤为明显。 为了提升用户体验,Android 8.0(API 级别 26)对应用在后台运行时可以执行的操作施加了限制。 本篇文章将介绍操作系统的一些变更,以及如何更新应用以使其能够在新限制下正常运行。

二、概览

多个 Android 应用和 Service 可以同时运行。 例如,用户可以在一个窗口中玩游戏,同时在另一个窗口中浏览网页,并使用第三个应用播放音乐。 同时运行的应用越多,对系统造成的负担越大。 如果还有应用或 Service 在后台运行,则会对系统造成更大负担,进而可能导致用户体验下降;例如,音乐应用可能会突然关闭。为了降低发生这些问题的几率,Android 8.0 对应用在用户不与其直接交互时可以执行的操作施加了限制。

应用在两个方面受到限制:

后台 Service 限制:处于空闲状态时,应用可以使用的后台 Service 存在限制。 这些限制不适用于前台 Service,因为前台 Service 更容易引起用户注意。

广播限制:除了有限的例外情况,应用无法使用清单注册隐式广播。 它们仍然可以在运行时注册这些广播,并且可以使用清单注册专门针对它们的显式广播。

请注意:默认情况下,这些限制仅适用于适配 Android 8.0(API 级别 26)或更高版本的应用。 然而,即使应用适配的 API 级别低于 26,用户也可以从 Settings 屏幕为任意应用启用其中大多数限制。

在大多数情况下,应用都可以使用 JobScheduler 作业克服这些限制。 这种方法允许应用安排其在未活跃运行时执行工作,不过仍能够使系统可以在不影响用户体验的情况下安排这些作业。 Android 8.0 提供针对 JobScheduler 的多项改进,让您可以更轻松地使用计划作业取代 Service 和广播接收器;如需了解详细信息,请参阅 JobScheduler 改进。

三、后台 Service 限制

在后台中运行的 Service 会消耗设备资源,这可能会降低用户体验。 为了缓解这一问题,系统对这些 Service 施加了一些限制。

系统可以区分前台和后台应用。 (用于 Service 限制目的的后台定义与内存管理使用的定义不同;一个应用按照内存管理的定义可能处于后台,但按照能够启动 Service 的定义又处于前台。)如果满足以下任意条件,应用将被视为处于前台:

  • 具有可见 Activity(不管该 Activity 已启动还是已暂停)。
  • 具有前台 Service ,通俗来讲:目前正在执行该service某个回调(Service.onCreate()、Service.onStart() 或 Service.onDestroy())方法中的代码。
  • 另一个前台应用已关联到该应用(不管是通过绑定到其中一个 Service,还是通过使用其中一个内容提供程序ContentProvider)。 例如,如果另一个应用绑定到该应用的 Service,那么该应用处于前台:

IME

壁纸 Service

通知侦听器

语音或文本 Service

如果以上条件均不满足,应用将被视为处于后台。

处于前台时,应用可以自由创建和运行前台与后台 Service。 进入后台时,在一个持续数分钟的时间窗内,应用仍可以创建和使用 Service。 在该时间窗结束后,应用将被视为处于空闲状态。 此时,系统将停止应用的后台 Service,就像应用已经调用 Service 的 Service.stopSelf() 方法一样。

在这些情况下,后台应用将被置于一个临时白名单中并持续数分钟。 位于白名单中时,应用可以无限制地启动 Service,并且其后台 Service 也可以运行。 处理对用户可见的任务时,应用将被置于白名单中,例如:

 处理一条高优先级 Firebase 云消息传递 (FCM)消息。
        接收广播,例如短信/彩信消息。
        从通知执行 PendingIntent。
        在 VPN 应用将自己提升为前台进程前开启 VpnService。

        在 Android 8.0 之前,创建前台 Service 的方式通常是先创建一个后台 Service,然后将该 Service 推到前台。 Android 8.0 有一项复杂功能:系统不允许后台应用创建后台 Service。 因此,Android 8.0 引入了一种全新的方法,即 startForegroundService(),以在前台启动新 Service。 在系统创建 Service 后,应用有五秒的时间来调用该 Service 的 startForeground() 方法以显示新 Service 的用户可见通知。 如果应用在此时间限制内未调用 startForeground(),则系统将停止此 Service 并声明此应用为 ANR

总结

默认情况下,这些变更仅影响适配 Android 8.0(API 级别 26)或更高版本的应用。 不过,即使应用适配的 API 级别低于 26 的,用户也可以从 Settings 屏幕中启用这些限制。您可能需要更新应用,使其符合新限制,约定如下:

1. 如果处于后台时您的应用需要创建一个前台 Service,请使用 startForegroundService() 方法,而非 startService()。

2. 如果 Service 容易引起用户注意,请将其设置为前台 Service。 例如,播放音频的 Service 始终应为前台 Service。 使用 startForegroundService() 方法创建 Service, 而非 startService()。

四、广播限制

如果应用注册为接收广播,则在每次发送广播时,应用的接收器都会消耗资源。 如果多个应用注册为接收基于系统事件的广播,则会引发问题:触发广播的系统事件会导致所有应用快速地连续消耗资源,从而降低用户体验。 为了缓解这一问题,Android 7.0(API 级别 24)对广播施加了一些限制,如后台优化中所述。 Android 8.0(API 级别 26)让这些限制更为严格,约定如下:

1. 适配 Android 8.0 或更高版本的应用无法继续在其清单中为隐式广播注册广播接收器。 隐式广播是一种不专门针对该应用的广播。 例如,ACTION_PACKAGE_REPLACED 就是一种隐式广播,因为该广播将被发送给所有已注册侦听器,让后者知道设备上的某些软件包已被替换。 不过,ACTION_MY_PACKAGE_REPLACED 不是隐式广播,因为不管已为该广播注册侦听器的其他应用有多少,它都会只被发送给软件包已被替换的应用。

2. 应用可以继续在它们的清单中注册显式广播。

3. 应用可以在运行时使用 Context.registerReceiver() 为任意广播(不管是隐式还是显式)注册接收器。

4. 需要签名权限的广播不受此限制所限,因为这些广播只会发送到使用相同证书签名的应用,而不是发送到设备上的所有应用。

隐式广播和显示广播

显示广播:发送广播时,指定具体的广播接收者类,例如:在Activity中可通过如下语句发送广播:

sendBroadcast(new Intent(MainActivity.this, TestReceiver.class)))。

AndroidMainfest.xml 静态注册:

<receiver android:name=".TestReceiver"><intent-filter><action android:name="android.intent.action.BOOT_COMPLETED"/></intent-filter>
</receiver>

隐式广播:发送广播时,不指定具体的广播接收者类,而是携带一些action、category或者data。例如:

sendBroadcast(new Intent("com.my.test.action"));

AndroidMainfest.xml中注册:

<receiver android:name=".TestReceiver"><intent-filter><action android:name="com.my.test.action" /></intent-filter>
</receiver>

Android O做了一系列变更,在清单文件中注册的隐式广播(除例外情况),运行在Android O上已经不起任何作用(不会收到广播回调),  这样子做是为了节省电量,提升续航,增强性能,提高用户体验。

举个例子:现在的手机中少则几十个应用多则上百,如果每个应用都注册监听CONNECIVITY_ACTION广播,想象一下,每当WiFi,数据流量网络状态发生变化时系统就会发出广播,此时所有的应用都被唤醒并执行任务,即使这些应用不在前台甚至没有运行,所以可想这是多么的耗费资源,特别是电量。

例外情况

有几种广播目前不会受这些限制,无论应用目标平台的 API 级别为何,都可以继续注册下列广播的侦听器,如下:

1. ACTION_LOCKED_BOOT_COMPLETED、ACTION_BOOT_COMPLETED:原因:这些广播只在首次启动时发送一次,并且许多应用都需要接收此广播以便进行作业、闹铃等事项的安排。

2.ACTION_USER_INITIALIZE、”android.intent.action.USER_ADDED”、”android.intent.action.USER_REMOVED”:原因:这些广播受特权保护,因此大多数正常应用无论如何都无法接收它们。

3. “android.intent.action.TIME_SET”、ACTION_TIMEZONE_CHANGED:原因:时钟应用可能需要接收这些广播,以便在时间或时区变化时更新闹铃。

4. ACTION_LOCALE_CHANGED:原因:只在语言区域发生变化时发送,并不频繁。 应用可能需要在语言区域发生变化时更新其数据。

5.ACTION_USB_ACCESSORY_ATTACHED、ACTION_USB_ACCESSORY_DETACHED、ACTION_USB_DEVICE_ATTACHED、ACTION_USB_DEVICE_DETACHED:原因:如果应用需要了解这些 USB 相关事件的信息,目前尚未找到能够替代注册广播的可行方案。

6. ACTION_HEADSET_PLUG:原因:由于此广播只在用户进行插头的物理连接或拔出时发送,因此不太可能会在应用响应此广播时影响用户体验。

7. ACTION_CONNECTION_STATE_CHANGED、ACTION_CONNECTION_STATE_CHANGED:原因:与 ACTION_HEADSET_PLUG 类似,应用接收这些蓝牙事件的广播时不太可能会影响用户体验。

8. ACTION_CARRIER_CONFIG_CHANGED、 TelephonyIntents.ACTION_*_SUBSCRIPTION_CHANGED、”TelephonyIntents.SECRET_CODE_ACTION”:原因:原始设备制造商 (OEM) 电话应用可能需要接收这些广播。

9. LOGIN_ACCOUNTS_CHANGED_ACTION:原因:一些应用需要了解登录帐号的变化,以便为新帐号和变化的帐号设置计划操作。

10. ACTION_PACKAGE_DATA_CLEARED:原因:只在用户显式地从 Settings 清除其数据时发送,因此广播接收器不太可能严重影响用户体验。

11. ACTION_PACKAGE_FULLY_REMOVED:原因:一些应用可能需要在另一软件包被移除时更新其存储的数据;对于这些应用,尚未找到能够替代注册此广播的可行方案。

12. ACTION_NEW_OUTGOING_CALL:原因:执行操作来响应用户打电话行为的应用需要接收此广播。

13. ACTION_DEVICE_OWNER_CHANGED:原因:此广播发送得不是很频繁;一些应用需要接收它,以便知晓设备的安装状态发生了变化。

14. ACTION_EVENT_REMINDER:原因:由日历提供程序发送,用于向日历应用发布事件提醒。因为日历提供程序不清楚日历应用是什么,所以此广播必须是隐式广播。

15. ACTION_MEDIA_MOUNTED、ACTION_MEDIA_CHECKING、ACTION_MEDIA_UNMOUNTED、ACTION_MEDIA_EJECT、 ACTION_MEDIA_UNMOUNTABLE、ACTION_MEDIA_REMOVED、ACTION_MEDIA_BAD_REMOVAL:原因:这些广播是作为用户与设备进行物理交互的结果(安装或移除存储卷)或启动初始化(作为已装载的可用卷)的一部分发送的,因此它们不是很常见,并且通常是在用户的掌控下。

16. SMS_RECEIVED_ACTION、WAP_PUSH_RECEIVED_ACTION:原因:这些广播依赖于短信接收应用。

上面16种虽然是隐式广播,但是目前还是可以正常接收到广播。

Android后台执行限制相关推荐

  1. android 后台执行js,android - 当应用程序在后台运行时,Android WebView消耗大量电能...

    我的Android应用程序中有一个WebView,并且此WebView运行的网站上带有相当多的Javascript.当我的应用程序在后台运行时,用户报告了高功耗,我希望这是由于此javascript. ...

  2. Android service后台执行定时任务

    Android 的定时任务 1,Java的API提供的Timer类 Android 中使用容易受手机的休眠系统影响(例如:手机休眠,导致了这个功能的停止). 2,Android的Alarm机制 Ala ...

  3. android服务中定时清理,Android中(Service )服务的最佳实践——后台执行的定时任务...

    Android中的定时任务一般有两种实现方式,一种是使用Java API里提供的Timer类,一种是使用Android的Alarm机制.这两种方式在多数情况下都能实现类似的效果,但Timer有一个明显 ...

  4. android后台文件下载库,android中如何下载文件并显示下载进度

    最近开发中遇到需要下载文件的问题,对于一般的下载来说不用考虑断点续传,不用考虑多个线程,比如下载一个apk之类的,这篇文章讨论的就是这种情形. 这里主要讨论三种方式:AsyncTask.Service ...

  5. Android后台杀死系列之三:LowMemoryKiller原理(4.3-6.0)

    本篇是Android后台杀死系列的第三篇,前面两篇已经对后台杀死注意事项,杀死恢复机制做了分析,本篇主要讲解的是Android后台杀死原理.相对于后台杀死恢复,LowMemoryKiller原理相对简 ...

  6. Android后台杀死系列之二:ActivityManagerService与App现场恢复机制

    本篇是Android后台杀死系列的第二篇,主要讲解ActivityMangerService是如何恢复被后台杀死的进程的(基于4.3 ),在开篇 FragmentActivity及PhoneWindo ...

  7. Android 系统性能优化(81)---Android后台优化系列-background optimization-初识低耗电模式

    Android后台优化系列-background optimization-初识低耗电模式 〇. 序 当我们手机屏幕电量的时候,我们或在游戏,或在看视频,或在上网,屏幕是一个很耗电的组件,在电量消耗方 ...

  8. Android 功耗优化(3)---Android后台调度与省电

    Android后台调度与省电 I. Handler: 在进程存活的期间有效使用, Google官方推荐使用. 相关机制可以参见: Android Handler Looper机制 简单易用. 稳定高效 ...

  9. Android 功耗(20)---Android后台调度与省电

    Android后台调度与省电 I. Handler: 在进程存活的期间有效使用, Google官方推荐使用. 相关机制可以参见: Android Handler Looper机制 简单易用. 稳定高效 ...

  10. Android后台耗电分析及优化

    原文见: 在路上的blog Android后台耗电分析及优化 一.什么是耗电优化? 二.耗电优化第一个方向:优化后台耗电 1.唤醒锁定操作卡住(前台&后台) 2.唤醒次数过多 3.WLAN扫描 ...

最新文章

  1. tp框架之Model类与命名空间
  2. 解决jar包乱码 in 创新实训 智能自然语言交流系统
  3. python中怎么计数_浅谈python中统计计数的几种方法和Counter详解
  4. python与C、C++混编的四种方式
  5. java整合flex
  6. 等保数据备份和恢复关键点,这些你该知道!
  7. 介绍一种在Xcode中删除一整行代码的快捷键设置,
  8. 机器学习笔记(四):kNN算法 | 凌云时刻
  9. 服务器接口文档详细 接口文档模板 规范 完整
  10. 【Java】日期格式化的三种方式
  11. DHCP八种报文及其详解
  12. Word中硬回车与软回车的区别和用法
  13. A protocol for Dying
  14. 用计算机绘制函数图像ppt,如何利用描点画函数图像课件制作
  15. 强推Markdown神器,一秒钟拯救微信公众号排版
  16. 山东大学计算机学院复试名单,山东大学2012计算机学院拟录取名单。
  17. word 删除带分节符的空白页
  18. 如何评估机器学习模型的商业价值
  19. Servlet 3.0
  20. asp.net实现视频在线播放

热门文章

  1. Mongodb节点同步失败状态“ RECOVERING ”恢复
  2. 改造 Firefox 浏览器——GitHub 热点速览 v.21.23
  3. 苹果公司的iPhone产品以及其历史
  4. 微信朋友圈怎么设置对单人开放?
  5. oracle11g闪回默认路径,rman 备份默认路径小结
  6. excel表格横向纵向变换_excel2016如何把纵向的数据变为横向
  7. canvas 的绘图模式 retained-mode(保存模式) 和 immediate-mode (立即模式)
  8. UnityEditor代码分享导出材质贴图和Mesh本体
  9. 这有几个常见的电脑故障解决方法,需要的朋友快来
  10. Hadoop十年解读与发展预测