如何通过 Android Vitals 修复应用质量问题并提高 Play 商店性能(第 1 部分)





0/5 (0投票)
深入探讨两个关键的稳定性问题——应用无响应事件和过度唤醒,以提高您的应用功能和质量。
对于应用开发者来说,没有什么比用户满意度更好的成功衡量标准了,而且最好是用户数量庞大。实现这一目标的最佳方法是拥有一款出色的应用,让人们愿意使用。但“出色”指的是什么呢?这归结为两件事:功能和应用质量。前者最终取决于您的创造力和选择的商业模式,而后者可以通过客观衡量和改进。
在去年进行的一项内部 Google 研究中,我们查看了 Play 商店中的一星评价,发现超过 40% 的评价提到了应用稳定性问题。相反,用户会持续以更好的评分和评价奖励表现最佳的应用。这会带来更好的 Google Play 排名,从而有助于增加安装量。不仅如此,用户还会更积极地参与,并愿意在这些应用中花费更多的时间和金钱。
因此,解决应用的稳定性问题可以显著影响其成功程度。
为了提供客观的质量衡量标准,以便您轻松发现应用中需要解决的稳定性问题,我们在 Play Console 中添加了一个名为 Android Vitals 的新部分。该部分会告诉您应用在性能和稳定性方面存在的问题,而无需在代码中添加任何检测工具或库。Android Vitals 会收集应用在各种设备上运行时关于您应用性能的匿名指标。它能为您提供规模化的信息,即使使用硬件实验室进行测试,也可能难以获得。
Android Vitals 可以提醒您注意的问题包括崩溃、应用无响应 (ANR) 和渲染时间。这些问题都会直接影响用户的体验和对您应用的看法。此外,还有一个类别是用户可能不会直接与您的应用关联的不良应用行为:那些比预期更耗电的行为。
在本文中,我将重点介绍其中两个问题:
- 过度唤醒。这会影响电池续航,如果用户无法及时充电,甚至可能导致其设备无法使用。这种行为很可能会导致用户迅速卸载您的应用。
- 应用无响应 (ANR) 事件。这些事件会记录您的应用界面冻结的情况。当界面冻结时,如果您的应用处于前台,会弹出一个对话框,让用户选择关闭应用或等待其响应。从用户的角度来看,这种行为和应用崩溃一样糟糕。用户可能不会立即卸载您的应用,但如果 ANR 持续存在,用户很可能会寻找替代应用。
过度唤醒
那么,什么是唤醒,以及什么时候它们会变得过度?
为了延长电池续航,在屏幕关闭后,Android 设备会进入深度睡眠模式,禁用主要的 CPU 核心。除非用户唤醒设备,否则设备最好能在此状态下保持尽可能长的时间。然而,在某些事件中,唤醒 CPU 并提醒用户非常重要——例如,闹钟响起或收到新的聊天消息时。这些提醒可以通过唤醒闹钟来处理,但正如我将要解释的那样,不一定非要如此。到目前为止,唤醒似乎是件好事,可以将重要事件引起用户的注意,但数量过多就会影响电池续航。
Android Vitals 如何显示过度唤醒?
Android Vitals 可以帮助您了解您的应用是否导致了过多的唤醒。收集到的关于您应用行为的匿名数据用于显示自设备充满电以来,每小时唤醒次数超过 10 次的用户所占的百分比。需要注意的关键是红色的图标;该图标表明您的应用已超出不良行为阈值。此阈值表明您的应用在 Google Play 上是表现较差的应用之一,您应该设法改进其行为。
是否有唤醒闹钟的替代方案?
在指定时间或间隔后唤醒设备的主要方法是使用 `AlarmManager` API 配合 `RTC_WAKEUP` 或 `ELAPSED_REALTIME_WAKEUP` 标志来安排闹钟。重要的是要谨慎使用此功能,并且仅在其他调度和通知机制无法更好地满足需求的情况下使用。以下是一些在使用唤醒闹钟时需要考虑的事项:
- 如果您需要根据网络数据响应显示信息,请考虑使用推送消息,例如通过实现 Firebase Cloud Messaging。使用此机制,您的应用将仅在需要时唤醒,而不是定期轮询新数据。
- 如果您无法使用推送消息并且依赖定期轮询,请考虑使用 `JobScheduler` 或 `Firebase JobDispatcher`(甚至 `SyncManager` 用于帐户数据)。这些 API 的抽象级别比 `AlarmManager` 更高,并提供以下用于更智能作业调度的优势:
- 批处理——多个作业将被批处理,让设备睡眠更长时间,而不是多次唤醒系统来运行作业。
- 条件——您可以指定必须满足才能运行作业的条件,例如网络可用性或电池充电状态。使用条件可以避免不必要地唤醒设备并运行您的应用。
- 持久性和自动回退——作业可以持久化(即使在重启后也能保留),并在失败时从自动重试中受益。
- Doze 兼容性——作业仅在 Doze 模式或应用待机模式没有限制时运行。
只有当推送消息和作业调度不适用于您的作业时,您才应该使用 `AlarmManager` 来安排唤醒闹钟。或者换个角度看,只有当您需要闹钟在特定时间响起,而与网络或其他条件无关时,唤醒闹钟才应该是必要的。
当 Android Vitals 显示过度唤醒时,您应该怎么做?
要解决过度唤醒问题,请确定您的应用在哪里安排了唤醒闹钟,然后减少触发这些闹钟的频率。
要确定您的应用在哪里安排了唤醒闹钟,请在 Android Studio 中打开 `AlarmManager` 类,右键单击 `RTC_WAKEUP` 或 `ELAPSED_REALTIME_WAKEUP` 字段,然后选择“查找用法”。这将显示项目中所有这些标志的实例。检查每一个,看看是否可以切换到更智能的作业调度机制。
您还可以将“查找用法”选项的范围设置为“项目和库”,以确定您的依赖项是否使用了 `AlarmManager` API。如果是,您应该考虑使用替代库或将问题报告给作者。
如果您决定必须使用唤醒闹钟,Play Console 会提供更好的分析数据,前提是您提供良好的闹钟标记,这些标记
- 在闹钟的标记名称中包含您的软件包、类或方法名称。这也有助于您轻松识别项目中设置闹钟的位置。
- 不要为闹钟名称使用 `Class#getName()`,因为它可能会被 Proguard 混淆。请改用硬编码字符串。
- 不要在闹钟标记中添加计数器或其他唯一标识符,因为系统可能会丢弃该标记,并且无法将其聚合为有用数据。
应用无响应
那么,什么是应用无响应 (ANR)?它如何影响用户?
对于用户来说,ANR 是他们尝试与您的应用互动时,界面冻结的情况。在界面冻结几秒钟后,会弹出一个对话框,让用户选择等待或强制退出应用。
从应用开发的角度来看,当应用通过执行耗时操作(如磁盘或网络 I/O)阻塞主线程时,就会发生 ANR。主线程(有时称为 UI 线程)负责响应用户事件以及每秒 60 次刷新屏幕上绘制的内容。因此,任何可能延迟其工作的操作都必须移至后台线程。
Android Vitals 如何显示 ANR?
利用收集到的关于您应用 ANR 事件的匿名数据,Android Vitals 提供了几个详细级别的 ANR 信息。主屏幕显示了您应用中 ANR 活动的摘要。这显示了用户遇到至少一次 ANR 的每日会话百分比,并分别报告了最近 30 天和前 30 天的情况。还提供了不良行为阈值。
详细视图,“ANR 率”页面显示了 ANR 率随时间的变化情况,以及按应用版本、活动名称、ANR 类型和 Android 版本划分的 ANR。您可以按 APK 版本代码、支持的设备、操作系统版本和时间段过滤这些数据。
您还可以从“ANR 和崩溃”部分获取更多详细信息。
ANR 的常见原因是什么?
如前所述,当应用进程阻塞主线程时,就会发生 ANR。这种阻塞可能出于几乎任何原因,但最常见的原因包括:
- 在主线程上执行磁盘或网络 I/O。这是迄今为止 ANR 最常见的原因。虽然大多数开发者都同意不应该在主线程上读写磁盘或网络数据,但有时我们都会忍不住这样做。在理想条件下,从磁盘读取少量字节可能不会导致 ANR,但这永远不是一个好主意。如果用户拥有一台闪存速度慢的设备呢?如果他们的设备因其他应用同时读写而承受极端压力,而您的应用在队列中等待执行“快速”读取操作呢?切勿在主线程上执行 I/O。
- 在主线程上执行长时间计算。那么内存计算呢?RAM 的访问时间不受影响,较小的操作应该是没问题的。但是,当您开始在循环中执行复杂计算或处理大型数据集时,很容易阻塞主线程。考虑调整包含数百万像素的大型图像的大小,或解析大量 HTML 文本以显示在 TextView 中。总的来说,最好让您的应用在后台运行此类操作。
- 从主线程运行同步 Binder 调用到另一个进程。与磁盘或网络操作类似,当跨进程边界执行阻塞调用时,程序执行会转移到您无法控制的位置。如果另一个进程很忙怎么办?如果它需要访问磁盘或网络来响应您的请求怎么办?此外,还需要将数据打包和解包以传递给另一个进程,这需要时间。最好从后台线程进行进程间调用。
- 使用同步。即使您将繁重操作移至后台线程,您仍然需要与主线程通信以显示进度或计算结果。多线程编程并不容易,并且在使用同步进行锁定以确保不阻塞执行时,往往很难做到。最坏的情况下,甚至可能导致死锁,使您的线程永远相互等待阻塞。最好避免自行设计同步,最好使用专门的解决方案,例如 `Handler`,将不可变数据从后台线程传递回主线程。
如何检测 ANR 的原因?
查找 ANR 的原因可能很棘手,以 `URL` 类为例。您是否期望 `URL#equals`(用于确定两个 URL 是否相同的方法)会阻塞? `SharedPreferences` 呢?如果您在后台读取 `SharedPreferences` 的值,可以在主线程上调用 `getSharedPreferences` 吗?在这两种情况下,答案是这些都是潜在的长时间阻塞操作。
幸运的是,`StrictMode` 工具可以帮助您找到 ANR 的原因。在调试版本中使用此工具来捕获主线程上的意外磁盘和网络访问。在应用启动时使用 `StrictMode#setThreadPolicy` 来自定义您想要检测的内容,包括磁盘和网络 I/O,甚至是通过 `StrictMode#noteSlowCall` 触发的自定义慢调用。您还可以选择 StrictMode 在检测到阻塞调用时如何提醒您:通过崩溃应用、日志记录或显示对话框。有关更多详细信息,请参阅 `ThreadPolicy.Builder class`。
在消除了主线程上的阻塞调用后,请记住在将应用发布到 Play 商店之前关闭 StrictMode。
消除过度的唤醒和 ANR 将提高您应用的质量和可用性,吸引更好的评分和评价,进而带来更多安装量。通过检查 Android Vitals,您可以快速轻松地了解您是否存在需要解决的问题。在代码中查找和解决这些问题并不总是那么直接,但有工具和技术可以帮助您高效地完成工作。
Android Vitals 还有更多可以帮助您的地方,我将在下一篇文章中介绍其中更多功能。此外,我将与同事 Fergus Hurley 和 Joel Newman 一起参加 2018 年的 Google I/O 大会,并在 5 月 8 日星期二下午 3 点 PT 举行的会议“Android Vitals:调试应用性能并收获回报”中发表演讲。如果您届时参会,请加入我们,或通过直播了解更多关于 Android Vitals、最新的 Play Console 和 Android Studio 工具以及可帮助您提高应用质量的见解。
如果您对 Android Vitals 有任何想法,请通过发送推文使用 #AskPlayDev 告诉我们,我们将从 @GooglePlayDev 回复,我们会在那里定期分享关于如何在 Google Play 上取得成功的最新消息和技巧。