首页 > 编程学习 > Android后台执行限制

Android后台执行限制

发布时间:2022/11/12 13:16:35

一、前言

        每次在后台运行时,应用都会消耗一部分有限的设备资源,例如 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种虽然是隐式广播,但是目前还是可以正常接收到广播。

Copyright © 2010-2022 dgrt.cn 版权所有 |关于我们| 联系方式