后台执行限制

每当应用在后台运行时,都会消耗设备的部分有限资源,例如 RAM。这可能会导致用户体验不佳,尤其是当用户使用需要大量资源的应用(例如玩游戏或观看视频)时。为了提升用户体验,Android 8.0(API 级别 26)会对应用在后台运行时可以执行的操作施加限制。本文档介绍了操作系统的变更,以及如何更新应用以便在新的限制下正常运行。

概览

许多 Android 应用和服务可以同时运行。例如,用户可以在一个窗口中玩游戏,同时在另一个窗口中浏览网页,并使用第三个应用播放音乐。同时运行的应用越多,系统的负载就越大。如果有其他应用或服务在后台运行,则会给系统增加负载,从而导致用户体验不佳;例如,音乐应用可能会突然关闭。

为降低出现这些问题的几率,Android 8.0 会限制应用在用户未直接与其互动时可以执行的操作。应用在两个方面受到限制:

  • 后台服务限制:当应用处于空闲状态时,其对后台服务的使用受到限制。这不适用于对用户更明显的前台服务。

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

在大多数情况下,应用可以通过使用 JobScheduler 作业来规避这些限制。这种方法可让应用在应用未活跃运行时安排执行工作,但仍可让系统以不会影响用户体验的方式安排这些作业。Android 8.0 对 JobScheduler 进行了多项改进,可让您更轻松地将服务和广播接收器替换为安排的作业;如需了解详情,请参阅 JobScheduler 改进

后台服务限制

在后台运行的服务可能会消耗设备资源,从而可能导致用户体验不佳。为了缓解此问题,系统会对服务施加多项限制。

系统会区分前台应用和后台应用。(出于服务限制的目的,后台的定义不同于内存管理所使用的定义;在内存管理方面,应用可能位于后台,但在启动服务方面,应用可能位于前台。) 应用满足以下任一条件即视为前台应用:

  • 它具有可见的 Activity,无论 Activity 处于启动还是暂停状态。
  • 它具有前台服务。
  • 另一个前台应用已关联到该应用(不管是通过绑定到其中一个服务,还是通过使用其中一个 content provider)。例如,如果其他应用绑定到该应用的以下任一项,则该应用处于前台:
    • IME
    • 壁纸服务
    • 通知侦听器
    • 语音或文本服务

如果以上所有条件均不满足,应用即视为后台应用。

当应用在前台运行时,可以自由创建和运行前台服务和后台服务。当应用进入后台时,它仍有几分钟的时间可以创建和使用服务。在该时间段结束时,应用会被视为空闲。此时,系统会停止应用的后台服务,就像应用已调用这些服务的 Service.stopSelf() 方法一样。

在某些情况下,系统会将后台应用放入临时许可名单中几分钟。当应用列入许可名单后,它可以不受限制地启动服务,并且其后台服务也获准运行。当应用处理对用户可见的任务时,系统会将其列入许可名单,例如:

在许多情况下,您的应用可以将后台服务替换为 JobScheduler 作业。例如,CoolPhotoApp 需要检查用户是否收到了好友分享的照片,即使该应用未在前台运行也是如此。以前,该应用使用后台服务与应用的云端存储空间进行检查。如需迁移到 Android 8.0(API 级别 26),开发者需要将后台服务替换为定期启动、查询服务器,然后退出的安排作业。

在 Android 8.0 之前,创建前台服务的常用方法是创建后台服务,然后将该服务提升到前台。在 Android 8.0 中,存在一个复杂问题:系统不允许后台应用创建后台服务。因此,Android 8.0 引入了新方法 startForegroundService(),用于在前台启动新服务。系统创建服务后,应用有 5 秒钟的时间来调用服务的 [startForeground()](/reference/android/app/Service#startForeground(int, android.app.Notification) 方法,以显示新服务的用户可见通知。如果应用未在时限内调用 startForeground(),系统会停止服务并声明应用存在 ANR

广播限制

如果应用注册接收广播,则每当发送广播时,应用的接收器都会消耗资源。如果有太多应用注册以基于系统事件接收广播,可能会导致问题;触发广播的系统事件可能会导致所有这些应用快速消耗资源,从而影响用户体验。为了缓解此问题,Android 7.0(API 级别 24)对广播施加了限制,如后台优化中所述。Android 8.0(API 级别 26)让这些限制更为严格。

  • 以 Android 8.0 或更高版本为目标平台的应用无法再在其清单中注册用于隐式广播的广播接收器,除非该广播仅限于该应用。隐式广播是指不以应用中的特定组件为目标的广播。例如,系统会将 ACTION_PACKAGE_REPLACED 发送到所有应用中的所有已注册监听器,以告知它们设备上的某个软件包已被替换。由于此广播是隐式广播,因此不会传递到以 Android 8.0 或更高版本为目标平台的应用中通过清单注册的接收器。ACTION_MY_PACKAGE_REPLACED 也是一个隐式广播,但由于它仅发送给软件包已被替换的应用,因此会传送给在清单中注册的接收器。
  • 应用可以继续在它们的清单中注册显式广播。
  • 应用可以在运行时使用 Context.registerReceiver() 为任何广播(无论是隐式广播还是显式广播)注册接收器。
  • 需要签名权限的广播不受此限制,因为这些广播只会发送到使用相同证书签名的应用,而不会发送到设备上的所有应用。

在许多情况下,之前注册了隐式广播的应用可以通过使用 JobScheduler 作业来实现类似的功能。例如,社交照片应用可能需要不时清理其数据,并且最好在设备连接到充电器时执行此操作。以前,应用会在清单中为 ACTION_POWER_CONNECTED 注册接收器;当应用收到该广播时,会检查是否需要进行清理。如需迁移到 Android 8.0 或更高版本,应用会从其清单中移除该接收器。而是由应用安排在设备空闲且充电时运行的清理作业。

迁移指南

默认情况下,这些变更仅会影响以 Android 8.0(API 级别 26)或更高版本为目标平台的应用。不过,用户可以通过设置界面为任何应用启用这些限制,即使应用以低于 26 的 API 级别为目标平台也是如此。您可能需要更新应用,以遵守新的限制。

检查应用如何使用服务。如果您的应用依赖于在应用处于空闲状态时在后台运行的服务,则需要替换这些服务。可能的解决方法包括:

  • 如果您的应用需要在后台运行时创建前台服务,请使用 startForegroundService() 方法,而不是 startService()
  • 如果用户会注意到该服务,请将其设为前台服务。例如,播放音频的服务应始终是前台服务。使用 startForegroundService() 方法(而非 startService())创建服务。
  • 找到一种方法,通过安排的作业来复制该服务的功能。如果服务不会执行对用户而言立即可见的操作,您通常可以改用安排的作业。
  • 使用 FCM 在发生网络事件时选择性唤醒应用,而不是在后台轮询。
  • 请推迟后台工作,直至应用在前台正常运行。

查看应用清单中定义的广播接收器。如果您的清单为受影响的隐式广播声明了接收器,您必须将其替换。可能的解决方法包括:

  • 通过调用 Context.registerReceiver() 在运行时创建接收器,而不是在清单中声明接收器。
  • 使用安排的作业检查是否存在会触发隐式广播的条件。