如何打造操作顺滑的APP

在此前一篇文章中,我们讨论了监控APP性能的重要性,在本文中,我们将展示如何具体做到这一点。我们和数个来自世界顶尖APP的开发者团队进行了交流,包括微信和Yahoo News Digest,讨论打造顺滑APP的最佳实践。根据我们的经验以及交流的结果,我们发现打造优秀APP的过程中,最重要的一点就是建立一套性能优化的规范流程

过程:测量,分析,优化
性能优化过程

持续测量APP的性能非常重要,这样才能第一时间检测出APP性能的下降。一旦检测到性能问题,第一步应该是分析出性能问题的根本原因。在分析过程中,你可能会需要进行更多的测量和更细节的性能数据,由此进入所谓“测量-分析循环”。即便分析出了问题的根本原因,仅仅是修改导致卡顿的几行代码还是不够,你必须重新进行测量,以确认性能问题被成功修复,而这也意味着更多的测量工作。

测量

影响用户体验(UX)的主要有两大性能指标。首先是响应时间:APP响应用户操作所需要的时间,例如启动APP,查看一则新闻,加载联系人列表,或者查看Facebook的一个页面。理想情况是APP对上述所有的操作都能瞬间响应,这样才可能打造出UX更棒,更吸引用户的APP。

一个至关重要而且独一无二的响应时间场景就是启动时间,APP的启动是给用户的第一感觉,而第一感觉往往是最重要的。实际上,Compuware的一则调查研究表明79%的用户在使用APP的过程中如果遇到1~2次问题就会卸载该APP

以下是我们NimbleDroid的一些建议,我们在软件性能优化方面有多年经验。

我们建议APP的启动时间不要超过2秒,因为这是大多数用户期待的APP启动时间。了解网站开发的人可能知道,47%的用户期待网页能在2秒以内完成加载,而手机APP的忍耐度会更低,因为他们使用手机时往往时间仓促,希望APP能尽快响应。

建议一:保证APP启动时间在2秒以内

第二个重要的指标就是顺滑程度。尽管整体上快速响应非常重要,响应的过程也应该非常顺滑,尽可能少的“卡顿”。用户能够轻易发现短暂的卡顿,即便是很细微的卡顿也会让用户觉得UX严重下降。总的来说,人眼能察觉到最短的的卡顿为22毫秒,而四分之一的人甚至可以察觉到2毫秒到16毫秒之间的卡顿,因此标准的刷新频率是60帧每秒(FPS)。

为了测量顺滑程度,你可以采集APP的FPS和每帧绘制时间数据。但需要明确的是,这些数据并不能指出问题的原因,它们并不能帮助你找到某个具体的导致APP卡顿的函数调用。

在安卓系统中,只有UI线程(APP执行的主线程)才能更新UI。为了达到60 FPS的帧率,UI线程必须在16毫秒内完成一帧的绘制,如果UI线程的函数调用超过了16毫秒,界面将会丢失一帧,产生一次短暂的卡顿。更严重的是,UI线程正在执行耗时函数,此时APP将无法响应用户的操作。

在实践中,保证UI线程的内一个函数调用不超过16毫秒基本不可能,另一个更可行的阈值是32毫秒,也就是每两帧之间丢失一帧。我们把执行时间超过这一阈值的方法称为夯方法,因为就是它们让一个APP被“夯住”。消除所有的夯方法能大幅提升APP的顺滑程度,全面提升用户体验。

建议二:消除所有的夯方法

测量UX相关的指标非常重要,但是我们应该多久测量一次呢?每次构建测量一次?每天的所有构建中测量一次?每次发布之前测量一次?在生产环境中,你应该尽可能多的进行测量,测量得越频繁,就能越早发现性能问题。雅虎团队会在每次发布之前进行一次测量,而微信团队则会在每天的所有构建中测量一次。

建议三:尽可能多的进行测量

分析

软件开发性能优化的关键之一是,了解到一系列常见的性能问题原因,并从代码中系统性的彻底移除。通过分析了下载量超过500万的APP的性能问题,我们发现开发者经常使用在PC上速度很快但是在手机上很慢的一些方法,手机的硬件相比于PC要低端很多。例如ClassLoader.getResourceAsStream()方法在MacBook Air上,对一个有3K资源的Jar包中调用需要7毫秒,而在Nexus 7 2013上,对一个有3K资源的APK文件调用则需要1700毫秒。实际上,安卓平台的getResourceAsStream实现会在第一次调用时执行很多额外操作,包括为APK文件中的所有资源建立索引,校验APK文件,解析manifest文件等,而上述这些操作都是非常消耗计算资源的,会导致APP性能急剧下降。getResourceAsStream导致Walgreens速度降低了1.7秒。NimbleDroid为大家准备了一个方法列表,大家应该在开发过程中避免使用,以免导致APP性能下降。

建议四:了解并避免常见的性能问题

有时候性能问题并不是你的代码导致的,而是第三方库引入的,这类问题很难排查。例如Java开发过程中非常流行的时间库org.joda.time,可能你在Java项目中使用过。但是在安卓平台上,在APP启动器件创建一个org.joda.time.DateTime()对象将会导致APP性能急剧下降,Yahoo Fantasy Sports因此导致了2秒的额外启动延迟。这是因为org.joda.time.DateTime()使用了getResourceAsStream()来从APK文件中读取时区数据。

建议五:避免使用存在性能问题的第三方库

优化

修复导致卡顿的代码可能是一个噩梦般的过程。可能有上百种原因会导致APP的卡顿,定位卡顿的根本原因可能需要几周的开发时间。尽管如此,还是有一些通用的建议是值得采纳的。你可以通过使用更高效的数据结构、算法以及实现,或者你可以在后台线程执行相对低效的代码(以及第三方库中的低效代码),这样就可以减少对UI线程的阻塞。遵循这些建议可以大幅提升APP的性能,打造更受用户欢迎的APP。

如何获得帮助

尽管上述过程可以帮助你打造更顺滑的APP,但这一过程可能需要大量时间,甚至需要一些奇技淫巧。而这正是我们所关注的部分:为安卓开发者提供快速、强大的性能优化以及分析工具。让开发者们只需要关注自己最擅长的部分:为用户打造伟大的产品。