点击“开发者技术前线”,选择“星标?”

13:21 在看|星标|留言,  真爱

翻译:可可翻译

英文:rom://http://greenrobot.me/devnews/facebook-engineer-improve-android-app/

背景

作为世界上最大的社交网络,Facebook的Android客户端面临着各种各样的使用环境(地理环境、Android设备以及移动网络等环境的差异)。也正是这个原因,为了检测自家Android客户端在发展中国家的性能表现,Android的产品经理、工程师在2013年的时候去了一趟非洲。

这群Facebook的工程师来到非洲之后,并在当地使用Facebook的最新版本的Android客户端。测试的结果的确让他们印象深刻:

  1. 当地的网络环境十分糟糕,App经常中断网络连接。

  2. 当地人民使用的Android设备内存小,导致App加载缓慢,而且经常崩溃。

  3. 他们的月流量在40分钟之内就用完了。

经过这个让人印象深刻的测试的之后,Facebook的工程师们开始对他们的Android客户端进行了一系列的优化。

他们发现在非洲打开 Android 版 Facebook app 时,因为硬体限制,再加上网络频宽狭窄,所以资料载入得很慢,app 也常常停止运作。结果,他们用了 Facebook app 40 分钟就烧光他们该个月的所有数据了!这个经验令到他们大悟,所以在返回基地之后,他们决定要将 Android 版 Facebook app 的运作表现改善。

他们指出 Facebook 的目标并不只是那些用到高阶手机和高速网络的人,而是将 Facebook 带给所有人,把「馀下的 50 亿人」连线。所以,他们买了几部不同的 Android 手机来做一个 Facebook app 大测试,至于这些手机是在哪里买,型号是什麽我们并不清楚,只知道它们缺乏内置储存空间,理应是一些非洲人常用的低阶手机吧。

启动优化

冷启动。指的是当应用还没准备好运行时,我们必须加载和构建整个应用。这包括设置屏幕底部的分栏菜单,确保用户是否被合适地登录,以及处理其他更多的事情。“引导”程序是在applicationDidFinishLaunching:withOptions:方法中开始的。

热启动。指的是应用已经运行但是在后台被挂起(比如用户点击了 home 健),我们只需要知道在何时应用进入后台。在这种情况下,我们的应用通过 applicationWillEnterForeground: 接收到前台的事件,紧接着应用恢复。

我们决定主要优化冷启动,主要有两个原因。

首先,冷启动其实是包括热启动的(冷启动初始化应用并获得摘要;热启动只获得摘要),所以有更多的地方需要优化和微调。

其次,冷启动需要做额外的初始化工作,所以相较而言更慢,导致需要更长的启动等待时间。

优化冷启动体验

我们把冷启动问题分解成三个阶段,进而我们可以有针对性地解决。每个阶段都有一些列变数和挑战。

请求时间:从应用启动到摘要请求离开设备(译者:应该是向服务器发送URL请求算结束时间)的时间。

网络时间:从摘要请求离开设备到服务器响应返回的时间。

响应处理时间:从响应返回到新数据展示在屏幕的时间。

我们直观上认为冷启动性能主要被网络请求和响应处理影响了。这个结论是由于我们假定我们在客户端花的时间比较少,并且我们设法让请求的获取更加快速。然而,当我们用 instrument 去检测时,我们发现数据非常出人意料。它展现出了完全不同的结果,我们发现摘要请求花了大部分时间。另外,响应的处理时间也非常短。因此,我们重新把优化的焦点放在初始化阶段。

性能优化

这里主要是改进了App在低端机上的性能问题。

  • 问题:单核的Android手机在启动Facebook的时候更慢,这是因为app在启动的时候并行初始化了多个模块。解决方案:在单核手机上延缓这些初始化过程到启动之后,甚至只有在某个模块要被使用的时候才开始初始化这个模块。

  • 问题:信息流在网络环境差时加载速度慢。解决方案:尽早地从服务器抓取信息流数据,用更多的时间来建立连接,并下载信息流的内容。

最终的效果是App的启动时间减少了50%。

数据处理效率的优化

非洲的旅程让工程师们发现流量在发展中国家非常昂贵,而且作为Facebook重要体验一环的照片则是流量花费的大头,于是为了让人民在不担心流量的前提下安心享用Facebook,工程师们决定对App里面的照片动刀:

  1. 寻找现有图片格式的替换者。经过工程师们的调研,在众多的图片格式中,最后工程师选择了Google的WebP。原因很简单:压缩效率高,而且对Android的支持好(毕竟就是Google提出来的)。使用 WebP 之后,相对于JPG格式的图片,流量省了将近 25% 到 35 %;相对于 PNG 格式的图片,流量省了将近80%。最重要的是使用WebP之后图片质量还没改变。

  2. 按照设备处理图片的能力来加载图片。在之前,Facebook的App都是统一加载最大分辨率的图片,这样做是为了让用户可以自由的缩放图片。后来改进之后,app最先加载的图片大小适合显示这个图片窗口大小一样。如果需要缩略图,app就只加载缩略图大小的图片,用户需要更高分辨率的图片,app也能加载,而且之前的统一加载最大分辨率的图片了。

  3. 调整缓存和重用图片的策略。工程师测试了不同的缓存策略,不同的缓存大小,最后综合出最优方案。

最后的效果也是讲流量花费减少了50%。

网络优化

由于许多地区的网络环境比较差,这让Facebook的App的体验也变得十分糟糕,于是工程师也对app的网络效率和可靠性进行了一番改进。

  1. 使用OkHttp。Facebook 很早就开始使用Square公司开发的OkHttp(一个开源的网络协议栈)了,现在Google 官方也从Android 4.4开始使用 OkHttp作为HttpURLConnection的默认实现了。OkHttp 支持在糟糕的网络环境下面更快的重试,并且还能利用 SPDY 协议进行快速的并发网络请求。

  2. 利用Okhttp调整图片的预先抓取算法,确保app中下载队列前面的图片被优先处理,防止队列阻塞时间过长。

Feed优化

Feed请求发送的初始化

所以为什么这个阶段花费了那么多时间呢?很多 iOS 应用并没有这样一个问题——他们在那个阶段并没有很多工作需要做,除了初始化视图控制器和发送网络请求。然而,对于 Facebook 来说,大部分时间被用来开始的时候去设置不同功能块。下面是我们应用中的主要功能块的流程概览。 

这看起来好像是很复杂的应用启动设置。但需要重视的是,这些功能块对于 Facebook 应用来说是非常重要的提升,可以提高应用体验,并且使得工程师能够在不同的应用规模下更快地开发。

正如我们所关注的这个流程,我们通过优化独立的部分获得了一些主要的成果。然而,由于未来支持新特性的初始化以及额外提供支持的基础设施,这些成果会慢慢地抵消掉。这使得我们重新考虑如何去解决问题。但我们重新开始,我们认为这个阶段的目标是简单地发送摘要的网络请求。但是为什么摘要请求发出去得这么慢?这是由于很多依赖被添加到摘要的初始化中了。然而,他们并不都是必要的 — 对于摘要请求来说,最少的需要一个有效的验证 token 以及摘要光标(新闻摘要的位置)。因此,我们减少了摘要请求的依赖,让它逐渐地更加接近应用的启动。这允许应用的剩余部分在摘要响应的同时进行初始化。由于这些重构,我们获得了显著的收益。

根据我们在第一阶段的经验,我们继续把这个阶段分解成更小的部分。网络请求/响应看起来像这样: 

我们注意到,一旦请求正在排队,发送请求出去之后就有一个时间间隔。这很好解释 — 在冷启动中,网络连接并不是一个开放的、安全的 TCP 连接。一个连接的建立需要三次握手,平均为几百毫秒。当摘要请求第一次发送时,无法避免要花掉这些时间。长远来看,这可以通过缓存 SSL 证书来解决。但是再次强调,我们退回来的目的并不是为了发送 TCP 请求,而是为了从服务器通过任何可能的方式获得请求信息。

我们提出了一个创造性的解决方案 — UDP 启动。本质上,我们在通过 TCP 发送摘要请求时,先发送一个编码过的包含摘要请求的 UDP 包到服务器。这样做的目的是唤醒服务器更早地去获取和缓存数据。当真正的摘要请求通过 TCP 到达时,服务器只需见到地从缓存内容中构造出响应,并发回客户端。这个技术使得我们可以减少几百毫秒的耗时。

当我们持续深入研究服务器端时,我们开始尝试使用 层-取(story-fetching)策略。过去我们已经做了一批摘要请求的 3+7 层。原因很简单:下载次数和被下载的层成正比。因此,把请求分割成两块,允许开始的三层先进来,其余的七个随后进来。通过提升我们的基础设施,我们已经能够升级为 1+1+X 策略,这已经接近于流了。这样就减少了服务器必须处理第一层的时间,并且能够减少下载的时间,使得可以在最快的时间内与用户交互。通过这样的努力,这样我们又减少了几百毫秒的耗时。

Feed响应处理

正如在前面提到的那样,我们以为在启动时会在这里花费大量的时间。但是这个想法被证明是错误的。更加使人好奇的是,我们注意到时间并没有花在处理和加工层上面。时间被花在运行应用服务和竞争资源上面。我们注意到这是我们优化网络和服务器时间的副作用,因为摘要请求返回得太早了。尽管大多数的服务是不重要的。因此,我们开发出一个简单的机制去序列化这些工作直到应用完成启动,并且使用先进先出的方式去执行。这样可以用更少的连接去处理所有层,大大地减少了获得响应和展示在屏幕之间的时间。

详细请看:Facebook APP Feed流的内存优化实践

经过优化后,图片加载慢或者加载 失败的反馈少了将近90%。

App文件大小优化

工程师在非洲的时候发现人们使用数量最多的手机磁盘空间很小,也就是说这给用户升级带来的障碍,进而可以推断这些人们因为手机的空间问题而一直使用旧版本的app,那么他们也就无法升级享受前面提到过的优化后的app体验。于是工程师开始致力于如何对app文件大小进行优化:

  1. 利用Google Play提供的功能为不同的Android版本、不同的Android屏幕分辨率的手机提供不同的安装文件。这样就可以在不同的设备上面进行功能的取舍了。

  2. 当然在这个过程中需要监测工具和测试工具来保证优化app文件大小之后app功能的正常性。现在Facebook的工程师已经开发出一套可以计算每个特性对Facebook Android App贡献了多大的空间。

经过优化之后的文件大小减少了将近65%。

总结

Facebook 工程师们的非洲之旅让他们更加理解了移动app性能、数据处理的有效性、网络的可靠性以及app的文件大小对发展中国家移动市场意味着什么。

工程师在这之后开始对每次app新添加的特性都会进行各方面的测试验证,而且Facebook还有一套工具可以直接获得用户对这些特性的反馈,而且工程师开始将这些实践延伸到 Messenger 和 Instagram 的Android App

---END---

选择”开发者技术前线 “星标?,内容一触即达。点击原文更多惊喜!

开发者技术前线 汇集技术前线快讯和关注行业趋势,大厂干货,是开发者经历和成长的优秀指南。

历史推荐

支付宝 App 启动性能优化

为什么我不推荐你用 Flutter 开发?

今日头条 App 屏幕适配方案落地研究

点个在看,解锁更多惊喜!

更多相关文章

  1. Android(安卓)时间间隔显示处理 1小时前 1天前 一个月前
  2. 【干货】Android应用架构笔记
  3. HttpURLConnection 源码分析
  4. Android根据当前时间获取前面的时间日期,或者之后的时间日期
  5. Android开发--Intent-filter属性详解 (转载)
  6. Android(安卓)SystemClock 应用
  7. Android获取Cookies,持久化PHPSESSID (OkHttp ;HttpClient ;Afin
  8. Android(安卓)搭建MVP+Retrofit+RxJava网络请求框架(二)
  9. "Kernel version" 中编译时间的前世今生

随机推荐

  1. Android(安卓)实现图片倒影效果
  2. Android学习笔记-Android初级 (二)
  3. Android学习视频大全
  4. 寒假练习一
  5. 探索FragmentTransaction#commit()抛出Il
  6. 仿照探探卡片滑动
  7. android有效显示图片Displaying Bitmaps
  8. Android(安卓)Service系列(十七)发送reques
  9. Lock Screen Orientation in Android
  10. 仿照DatePickerFragment实现的TimePicker