Google开发者YouTube频道发布了探讨Android性能模式的16个视频, 列出了开发者在创建应用时容易出现的一些性能问题,同时提供了很多处理建议。本文是对这些问题和建议的总结。 渲染性能101。 这一系列视频的讲师是Colt McAnlis,据他介绍,不当的渲染是Android上大部分性能问题的根源。如果一个Activity需要16毫秒以上的时间来准备在屏幕上渲染下一 帧,系统将放弃这一帧。应用的用户会感觉滑动不流畅,或者变换有延迟,从而导致体验不好。McAnlis推荐了很多用于检查此类问题的工具:Hierarchy Viewer、Traceview、Profile GPU Rendering、Debug GPU Overdraw和GPU View Updates。 建议尽量减少失效(invalidation)和布局(layout)的数量。前者可以用Developer Option Show GPU View Updates可视化地观察,而后者可以使用Hierarchy Viewer来分析。 过度绘制。过度绘制衡量的是一个特定的像素在一帧中被绘制的 VSYNC。开发者应该注意帧率变化,尤其是当帧率从高于屏幕刷新率突然掉到低于屏幕刷新率时。这会导致动画出现延迟,用户很容易感知到。 Profile GPU Rendering。 从Developer Options设置可以访问这个工具,它能够从屏幕上活动的所有Android Activity生成性能图,这些Activity通常包括通知和导航条,再就是活动的应用。一帧的时间在16毫秒以下为宜。性能图会包含所有和渲染相关 的主要活动的计时信息,这些活动包括更新显示列表、执行显示列表和处理glSwapBuffers。 60 fps。要让人眼对复杂动画有不错的感受,帧率最少要达到60 fps。保持60 fps的帧率并避免变化很重要。 定制视图。 有些过度绘制优化,比如不去绘制完全被遮盖的组件,但是当为了创建定制的视图而覆盖onDraw()方法时,渲染过程可能会缺少这样的优化。为尽量减少过 度绘制,建议使用canvas.clipRect()来指定定制绘制的精确区域。此外,应该使用quickReject()来确定某个区域是不是在剪掉的 矩形之外,如果没有必要,应该避免浪费时间绘制这个区域。 内存搅动。 为大量很快就会被丢弃掉的小型对象重复分配内存,会致使垃圾收集器多次介入,如果这些时间正是在16毫秒的窗口绘制时间内,可能会导致丢帧。借助 Android Studio Memory Monitor,开发者可以将垃圾收集活动以可视化方式显示出来,并确定是否有过多的垃圾收集。之后可以利用Allocation Tracker来确定这些内存对象从何而来。然后修复可能导致问题的相关代码,从而避免某些内存分配,或者是把这些分配移到循环之外。此外,对象不应该在 onDraw()内分配,因为这个方法1秒会调用很多次。如果应用确实需要大量很快就要丢弃的对象,建议使用对象池,一次创建,多次复用,从而避免垃圾收 集。 内存泄漏。 内存泄漏使垃圾收集消耗的时间变长,这又会影响帧率。为确保在用户离开某个Android Activity之后,不会出现内存泄漏,McAnlis建议创建一个不需要消耗内存,或者只需要消耗极少内存的空Activity,转到这个空的 Activity并强制执行一次垃圾收集。建议在转移之前和之后,使用Android Studio中的堆和分配跟踪工具来确定这个Activity是否有内存泄漏。 电量消耗。根据普渡大学和微软的一篇研究论文(PDF), 大约70%的电量是被第三方广告模块消耗的,它们会执行数据分析、位置发现和广告下载等操作。只有30%的电量是应用中实际活动消耗的。Google建议 开发者仔细处理电量消耗问题,因为这是用户最关心的。最重要的建议是,除非绝对必要,不要将设备从睡眠中唤醒。如果必须唤醒,建议使用 WakeLock,并设置一个超时时间,以确保如果应用出现问题,设备可以回到睡眠状态。另一个思路是使用AlarmManager.setInexactRepeating() ,将唤醒操作和另一个活动结合起来,从而节省电量。 可以将某些CPU密集型操作推迟到连上充电器并连接到WiFi时,或者将多个工作组合到一次唤醒操作中。这可以借助JobScheduler API,它支持将某些工作延迟一段时间。还有一个建议,要小心地使用网络连接,因为在发送完一个网络请求和接收到一个响应之后,设备要保持至少5秒钟的唤醒状态,以备从服务器传过来的另一个数据包。 McAnlis还建议利用Settings|Battery和Battery Historian 工具提供的电量消耗详情来监控应用随时间变化的耗电情况。 |