为了提供一个客观的质量衡量标准,使你可以轻松发现应用需要解决哪些稳定性问题,我们在 Play Console 中添加了一个名为 Android vitals 的新模块。这个模块可以告诉你应用程序的性能和稳定性问题,而不需要在代码中添加仪器或库。当你的应用程序运行在众多设备上的时候,Android vitals 会收集关于应用程序性能的匿名指标。即使在使用硬件实验室进行测试时,它也会以其他方式难以获得的规模为你提供信息。
Android vitals 可以提醒你的问题包括崩溃、应用程序无响应(ANR)和渲染时间。这些问题都直接影响你的用户对应用的体验和看法。此外,还有一类用户可能不会直接与你的应用关联的不良应用行为:比如耗电的速度比预期的要快。
在本文中,我将着眼于以下两个问题:
- 过度唤醒。这会影响电池的续航时间,如果用户无法及时充电,可能会导致他们无法使用设备。这种行为很可能会让用户迅速卸载你的应用。
- 应用程序无响应(ANR)事件。这些事件发生在你的应用程序 UI 冻结的时候。发生冻结时,如果你的应用位于前台,会弹出对话框让用户选择关闭应用或等待响应。从用户的角度来看,这种行为与应用崩溃一样糟糕。用户可能不会立即卸载你的应用,但如果 ANR 持续存在,用户很可能会寻找替代的应用。
过度唤醒
那么,唤醒是什么以及它们何时变得过度呢?
为了延长电池的续航时间,屏幕关闭后,Android 设备将通过禁用主 CPU 内核进入深度睡眠模式。除非用户唤醒设备,否则设备会尽可能长时间地保持在此状态。但是,有一些重要事件需要唤醒 CPU 并提醒用户,例如,当闹钟响起或有新的聊天消息到达时。这些警报可以通过唤醒警报(wakeup alarm)来处理,但正如我将要解释的那样,这并不是必须的。到目前为止,唤醒似乎是一件好事,它可以显示重要的事件引起用户的注意,但是如果有太多这种事件那么电池寿命就会受到影响。
Android vitals 如何显示过度唤醒?
了解你的应用是否在驱动过多的唤醒是 Android vitals 的重要任务。收集的有关你应用行为的匿名数据用于显示自设备完全充电后,每小时经历超过 10 次唤醒的用户的百分比。要查看的关键点是一个红色的图标;这个图标告诉你,你的应用已超出不良行为阈值。而这个阈值表示你的应用属于 Google Play 上表现较差的应用,你应该考虑改善其行为。
唤醒警报是否有其他替代方法?
在指定时间或间隔后唤醒设备的主要方法是使用 AlarmManager API 的 RTC_WAKEUP 或 ELAPSED_REALTIME_WAKEUP 标志来安排警报。但是一定要注意谨慎地使用此功能,而且只有在其他调度和通知机制不能更好地提供服务的情况下。当你想要使用唤醒警报时,请注意考虑以下几点:
-
如果你需要根据网络返回的数据来显示信息,可以考虑使用消息推送来实现,例如 Firebase Cloud Messaging。使用这种机制而不是定期拉取新数据,你的应用只有在需要时才会被唤醒。
-
如果你无法使用消息推送并且依赖定期拉取,可以考虑使用 JobScheduler 或者是 Firebase JobDispatcher(甚至是 SyncManager 来获取帐户数据)。这些是比 AlarmManager 更高级别的 API,而且为更智能的定期任务提供以下好处:
A) 批处理 —— 许多任务将被批量处理以使设备睡眠时间更长,而不是多次唤醒系统来执行这些任务。
B) 条件 —— 你可以指定必须满足某些条件才能执行你的任务,例如网络可用性或电池的充电状态。使用这些条件可以避免不必要的设备唤醒和应用运行。
C) 持续性和自动重试 —— 任务可以持续执行(即使重新启动也可以),并且可以在发生故障时自动重试。
D) Doze 兼容性 —— 任务只有在不受 Doze 模式限制或应用程序待机时才会执行。
只有当消息推送和定期任务不适合你的工作时,你才应该使用 AlarmManager 安排唤醒警报。或者从另一个角度来看,只有当你需要在特定时间启动闹钟时才需要使用唤醒警报,无论网络或其他条件如何。
Android vitals 显示过度唤醒时你应该怎么做?
要解决过度唤醒的问题,请先确定你的应用在哪些地方设置了唤醒警报,然后降低触发这些警报的频率。
要确定你的应用在哪些地方设置了唤醒警报,请在 Android Studio 中打开 AlarmManager 类,右键单击 RTC_WAKEUP 或 ELAPSED_REALTIME_WAKEUP 字段并选择 “Find Usages”。这将显示你项目中用到这些标志的所有实例。审查每一个实例,看看你是否可以切换到更智能的定时任务机制中的一种。
你还可以在 Find Usages 选项中将范围设置为“项目和库”,以确定你的依赖库是否使用了 AlarmManager API。如果是,你应该考虑使用替代库或向作者报告这个问题。
如果你决定必须使用唤醒警报,那么如果你提供了符合以下要求的警报标签,则 Play Console 可以提供更好的分析数据:
- 在你的警报标签名称中包含你的包名、类名或方法名。这也可以帮助你轻松识别警报设置在你源码中的什么位置。
- 请勿使用 Class#getName() 作为警报名称,因为它可能会被 Proguard 混淆。改用硬编码的字符串。
- 不要将计数器或其他唯一标识符添加到警报标签,因为系统可能会丢弃标签,而且无法将它们聚合成有用的数据。
应用程序无响应
那么,什么是应用程序无响应(ANR),它又是如何影响用户的呢?
对于用户来说,ANR 是当他们尝试与你的应用进行交互时,该界面被冻结。界面保持冻结几秒钟后,会显示一个对话框,让用户选择等待或强制应用程序退出。
从应用程序开发的角度来看,当应用程序因为执行耗时操作(如磁盘或网络读写)阻塞主线程时,就会发生 ANR。主线程(有时称为 UI 线程)负责响应用户事件并刷新屏幕上每秒绘制六十次的内容。因此,将任何可能延迟其工作的操作都转移到后台线程是至关重要的。
Android vitals 如何显示 ANR?
使用收集到的有关你应用 ANR 事件的匿名数据,Android vitals 提供了有关 ANR 的多个级别的详细信息。主屏幕显示你应用程序中发生 ANR 的 Activity 的概况。这显示了用户经历过至少一次 ANR 的每日会话的百分比,以及之前最近 30 天的单独报告。还提供了不良行为的阈值。
详细信息视图的 ANR 比例页面显示了 ANR 比例随时间变化的详细信息,以及按应用版本、Activity 名称、ANR 类型和 Android 版本显示的 ANR 信息。你可以通过 APK 版本号、支持的设备、操作系统版本和时间段来过滤这些数据。
你还可以从 ANRs & crashes 部分获取更多详细信息。
ANR 的常见原因是什么?
如前所述,当应用程序进程阻塞主线程时就会发生 ANR。几乎任何原因都可能导致这种阻塞,但最常见的原因包括:
- 在主线程上执行磁盘或网络读写操作。这是迄今为止 ANR 最常见的原因。虽然大多数开发人员都认为你不应该在主线程上读取或写入数据到磁盘或网络,但有时我们总会无意间这么做。在理想情况下从磁盘读取几个字节可能不会导致 ANR,但是这绝不是一个好主意。如果用户使用的设备闪存很慢怎么办?如果他们的设备受到来自其他应用程序同时读取和写入的巨大压力,而你的应用程序在队列中等待执行“快速”读取操作时又该怎么办?切勿在主线程上执行读写操作。
推荐学习资料
-
Android进阶学习全套手册
-
Android对标阿里P7学习视频
-
BAT TMD大厂Android高频面试题
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
282)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!