做者 凤萧 蚂蚁金服·数据体验技术团队php
不少企业都会特别注重本身产品的体验,尤为是移动端,那移动端的体验为何这么重要?首先体验自己就很重要,好的体验带给用户的感觉是大相径庭的,用户选择使用一个产品除了产品自己功能知足需求以外,还有一个更重要的缘由就是产品用起来“爽”,产品整个使用流程必然是温馨天然,才能受到大众喜好;此外,产品体验已成为市场竞争力之一,借用人人都是产品经理上面对体验的论述:css
当技术已再也不是产品核心竞争力时,产品竞争的实质就是用户体验之争。html
若是产品不能让用户身心感到愉悦和温馨,他们极可能会迅速使用其余替代品,对于 toC 的产品尤其明显,产品体验糟糕必然会被市场淘汰。可是体验是一个很庞大的话题,有不少方面会影响产品的体验,如性能、UI、交互以及人性化的功能等等,本文抛砖引玉,只从技术层面的某几个方面聊聊移动端的体验优化,主要以 Android 为切入点,IOS 大部分优化方向与 Android 相似。考虑到市面上绝大多数 APP 都是 Native+H5 相结合的应用,且本人项目中也大量使用 H5 页面,所以将从 Native 端和 H5 端分别总结如何优化体验。前端
一直在思考从技术层面上,Native 端什么样才称得上是体验佳的产品,有什么评判标准,从过往经验来看,我的以为应该具有如下基本特质:android
做为技术人须要重点把控的是前 4 点,第 5 点可能更多须要设计同窗介入,根据以往的经验,能够从如下几个方面着手:启动优化
,内存优化
、UI 渲染优化
、网络优化
等,内存和 UI 渲染的优化主要针对卡顿问题,网络优化中一个重点涉及的对象是缓存和弱网支持,每个方面均可以独立成文进行专门的探索,本文只提供一些主流的优化思路供参考,不详细展开。git
虽然如今手机内存配置愈来愈好,可是内存依然是很吃紧的资源,由于系统对 APP 内存占用有限制(具体大小依不一样手机厂商而异)。内存的优化首先要避免大量的内存泄露,可使用leakcanary进行自动检测,若要深刻分析,可使用 Android Studio
手动 dump 内存下来用MAT工具进行分析,发现其中潜在的内存泄露对象。其次是尽可能使用成熟的图片开源框架,如Glide或者Picasso等展现图片或者 Gif。github
内存优化除了注意内存泄露
,还要关注内存的抖动
,出现的缘由通常是大量频繁的建立对象,致使频繁触发 GC,以至于 APP 使用卡顿,好比常见的场景是在自定义控件的 onDraw 方法建立对象,由于 onDraw 方法会频繁调用,在 onDraw 方法中建立大对象会致使内存急剧增加,触发 GC 致使卡顿。所以要尽可能避免在循环体中建立对象,能够考虑使用对象池一次建立多处复用来规避内存抖动。web
UI 渲染性能关系到 APP 的流畅度,16ms 内未能完成一次绘制就会出现掉帧,给人感受就是页面卡顿,响应不及时。移动端上致使渲染性能降低的缘由和解决的通常套路:后端
布局要避免没必要要嵌套,以使用 Hierarchy View 进行辅助查看布局层级关系,来识别嵌套是否合理;同时要根据具体场景合理使用哪种布局,如 RelativeLayout 不能滥用,对于复杂布局能够用 ConstaintLayout 代替;此外还可使用 viewstub 进行延迟加载布局,用 merge 和 include 进行布局复用。浏览器
过分绘制的出现是由于在重叠的层级结构中,一些不可见的部分由于某些缘由,如设置了背景色,也会出如今绘制操做中,致使这块重叠区域的像素被屡次绘制,那明显是浪费计算资源。可使用简单方法识别过分绘制是否严重,在 Android 系统中开发主菜单里面打开「调试 GPU 过分绘制」开关就能看到界面 UI 元素被不一样的颜色块标注(以下图),
颜色从原色——蓝色——绿色——粉色——红色依次表明过分绘制严重程度从低到高,通常而言须要关心红色的色块 UI 元素,由于它有严重的过分绘制,是有优化空间的。个人通常解法是去掉布局背后没必要要的背景色,固然还有其余因素会致使过分绘制,如包装的自定义控件,自己由于不注意避免过分绘制的影响,在使用的时候就自带严重的过分绘制问题。
主线程(UI 线程)不能有复杂耗时的计算任务,不然会致使 UI 无响应,卡顿,最终致使 ANR 的发生。
最主要的思路避免把所有的初始化任务放在 Application 中,可使用子线程或者懒加载的方式来处理初始化任务;另外常规套路是会给第一个 Activity 设置 theme,这样打开 APP 瞬间看到不是白屏,给用户的感受就是启动速度获得改善。
移动互联网时代,H5 页面无处不在,几乎 80%以上的 APP 都有 H5 页面的影子,一份代码多端运行且能快速部署的优点,让 Hybrid 开发成为不少 APP 的标配。虽然 Hybrid 在体验上老是赶不上 Native 的体验,甚至在处理不当的状况下,糟糕的体验会让不少企业选择使用其余技术栈,可是 Hybrid 依然是不少公司使用的主流技术。我的认为,在对页面体验没有过高要求的状况下,Hybrid 依然是当下最佳的开发方式。要实现较好的体验,须要花费心思对 H5 页面进行优化,我以为有三个方向能够进行优化:
本文只从影响体验最重要的指标——白屏时间来聊聊如何进行优化,响应流畅度和页面渲染性能由于缺少实践经验,这里就不班门弄斧。
先分析下在移动端从用户点 H5 连接到页面渲染完成展现给用户,须要经历的粗略过程,示意以下图:
这里的渲染包含了 html、js、css 的解析,组装成 Render Tree 以及最后的绘制。粗略的估算,能够将耗时拆解为:
总耗时(t) = Webview 初始化耗时(t1) + 下载静态资源耗时(t2) + 数据请求耗时(t3) + 渲染耗时(t4)
其中 Webview 初始化、静态资源加载以及数据请求占用的耗时是比较多的,且这个耗时页面必定处于白屏阶段,如下对这三块给出一些常规的优化方案,渲染的耗时优化本文不论述。
静态资源主要指 html,js 和 css 资源,对于单页应用而言主要是 js 和 css,下图是我参与的项目中页面第一次打开时的静态资源请求状况(无浏览器缓存): 
从页面请求能够看到,其中 1.js 的下载是比较耗时的,是应用比较核心的 js 文件,必须等待此文件下载完成,才有可能继续后面的页面渲染。在几乎零优化的状况下能够看到耗时接近 800ms,仍是有很大的优化空间的。下面从前端视角和客户端视角来说解下静态资源优化的思路。
从前端的角度入手,能够有如下几个优化手段:
从客户端角度入手,实际上是客户端预加载静态资源或者提早内置到手机本地,所以客户端须要维护要加载到本地的静态资源列表,当页面打开时,拦截 webview 资源请求,根据资源 URL 路由到本地对应资源,这样的速度是极快的。本身去实现该过程会比较繁琐,上述过程的实现其实就是离线包方案,离线包机制能帮助作好静态资源更新、管理、拦截、重定向以及异常链路,如支付宝的 nebula 容器自带离线包解决方案。可是单个离线包不宜过大,通常 0-4M,对于较大应用有时候会突破这个限制,实际项目中将一些共用通用的框架资源(如 React、lodash、moment)提取出来,提早预置 APP 中来解决单个离线包大小限制,除此以外成熟的离线包方案自带公共包机制,也能够解决离线包过大的问题。下图是通过优化后资源请求状况,
能够看到使用离线包外加预置公共资源方案以后,静态资源的请求耗时直接降到 200ms 如下,几乎全部的静态资源在首次打开页面就所有走本地存储,优化效果仍是很明显的。 
一些在浏览器中打开的 web 页面可能不太注重数据请求的优化,在移动端,因为追求极致体验,每每数据请求也是有很大优化空间的。如下总结几点数据请求的优化思路。
单页面数据请求接口压缩到 1—2 个,过多的网络接口请求,一是会有过多建链和断链的网络耗时,二是会提升接口请求失败率。尤为是相互依赖的接口,能够考虑将请求进行合并。
数据请求提早。首屏的数据若是在打开 webview 的瞬间已经准备完毕,那基本很快能够将页面展现出来。所以在对首屏性能要求较高的场景下,能够考虑将接口请求提早在页面打开前,如 APP 打开后就提早开始缓存用户可能要打开的页面数据,在用户打开页面时从本地缓存获取数据。在实际项目中请求提早涉及两个现实的问题,请求具体时机以及缓存问题。
webview 是移动端浏览器实例,几乎具有 PC 端浏览器的绝大多数能力,客户端在使用 webview 打开 H5 页面前,须要实例化 webview 对象,其初始化的过程在 android 系统中须要大约 500ms 以上的时间。有一种手段是使用对象复用机制,提早建立 webview 对象池,须要使用 webview 时直接从池中获取初始化完毕的对象,这种相似于线程池的方式能够避免每次打开 H5 页面都要初始化 webview 实例,从而提高页面打开速度。
还有另一个彻底不一样思路来优化移动端 H5 页面打开速度,那就是服务端渲染,也称之为 SSR,简单来说就是服务端将页面的 html 和数据提早组装好再传递给浏览器,浏览器只负责解析 html 和展现,所以首屏渲染较快。可是会给服务端增长压力和复杂度,现实中须要综合考虑利弊以及 ROI 来选择是否使用 SSR 方案。
本人参与的项目在 H5 页面只针对静态资源和数据请求进行了优化,完成后得到效果仍是较为理想的,见下图绿色线是优化以后页面打开的平均白屏时间,蓝色是优化前的平均白屏时间,能看到优化成效仍是至关可观的,若是能将 webview 的初始化时间也优化掉,基本上能达到页面秒开。
以上是结合本身项目以及以往的经验总结的较为常规的针对移动端体验优化的思路,比较浅显,其实每个优化思路虽说起来简单,可是在实践中会由于各类因素(如投入产出比,先后端资源协调等)致使夭折,并且优化思路也须要分场景,须要因地制宜选用不一样的方案。每个优化思路均可以写长文进行深刻探讨,体验优化是一个马拉松,须要长期持续的投入,有兴趣的欢迎一块儿交流。
github blog 原文链接