书接上文,Android 性能优化(一):闪退、卡顿、耗电、APK
从用户体验角度有四个性能优化方向:
卡顿的场景通常与用户交互体验最直接,分别为UI、启动、跳转、响应四个方面,如下图所示。
主要有两大因素:
主要是绘制和刷新的卡顿,典型表现在页面的列表的滑动加载和刷新。
针对绘制可以使用懒加载,针对刷新可以使用局部刷新。详情参考:
(四)RecycleView 滑动到置顶、Adapter局部刷新
启动速度是用户第一印象,过长会让用户失去耐心; 根据行业数据统计,启动速度与用户留存有着直接相关;
对于开发者来说,通过各种技术手段来提升启动性能缩减启动时长,对整站业务的各项指标提升都会有较大帮助。因此,启动优化是各个客户端团队在体验优化方向上十分重要的一环。
在计划优化立项之前,先确定两件事。
衡量一个任务是否要启动有两个关键指标:“投入产出比”、“产出风险比”。
有个比较简单的方法就是对标,比如,竞品App或主流App。
当然,启动优化最终目标是“秒开”,即需要 1s 内完成用户的启动流程。
工作的价值体现就在于建设丰富的数据大盘来明确以什么形式、从什么角度、监控什么指标。
启动优化的整体监控可以为:
业内常见的app启动过程阶段一般分为「启动阶段」和「首刷阶段」。
Application
的onCreate,终点
Activity
的 onWindowFocusChanged
() 。
Activity
的onCreate,
终点列表的onAttachedToWindow() 。为了确保启动优化量化指标的数据能稳定和完整。因此,排除其他启动场景的统计:
站外push、deeplink
拉起。Android Studio 自带的Profiler工具。
如果是 Android 10 及以上就用 Perfetto。
在App的启动流程中,有非常多的启动任务全部在Application的onCreate里被执行,有主线程的有非主线程的,但是不可避免的是,二者都会对启动的性能带来损耗。所以我们需要做的第一件重要的事情就是“启动任务重排与删减”。
可以把启动任务按优先级分类:
- TaskManager.getInstance().beginWith(A)
- .then(B)
- .then(C, D)
- .then(E)
- .enqueue();
- TaskManager.getInstance().runAfterStartup({ xxx; })
通过任务的大致非精细化的排布,我们不仅仅可以对启动任务能够很好的进行监控,还可以更加容易的找出不合理项。
从业务的角度出发,找到对启动流程影响最大的业务为切入点,尝试寻求更优的解法。
根据业务流程进行如下考虑:
当App启动时,会先进入SplashActivity等广告接口返回展示广告,然后转进MainActivity。这个流程对性影响最大的点是:等广告接口时,无法对后续业务做预加载,业务都在MainActivity。另外,启动阶段需要连续启动两个Activity,至少带来 百毫秒 级别的劣化。
合并前后,流程图如下:
广告原先是以Activity的形式在展现,现在被抽离成 View 的形式去承载逻辑,在 onCreate 中,广告View添加进 DecorView中,完成对首页布局的遮罩。在广告View展示logo图时,底下首页框架是可以进行预加载和渲染。
补充注意事项:
MainActivity 作为launchAtivity的单实例问题。App从后台进前台,其他二级页面跳转到首页的依然走生命周期的现象。MainAcitvity 的 launchmode 需要设置为 singleTop。
首页弹窗管理器需要延迟初始化。在广告View覆盖在上面时,先暂停弹层管理器的生命周期,避免出现其他内容盖住广告。
一般MainActivity中的Tab会以fragment形式被提起预加载。而首刷阶段的终点是在首页列表View的onAttachedToWindow()生命期中。
因此,可以考虑其他Tab进行延迟加载和懒加载。即用户不迫切切换Tab,就在首页View绘制时进行预加载;否则就在用户点击Tab切换事件中进行加载(可能卡顿劣化,需风险评估)。
比如,广告View可以在接口返回数据且经过素材校验后,再进行布局的加载。类似的Banana位、搜索框、其他图片广告等。
其他:使用wrap_content会增加measure计算成本;kotlin by lazy,动态内容加载的场景等。
过度绘制是指在屏幕上的某个像素在同一帧的时间内被绘制了多次。
在多层次重叠的 UI 结构中,如果不可见的 UI 也在做绘制的操作,就会导致某些像素区域被绘制了多次,从而浪费了多余的 CPU 以及 GPU 资源。
可以通过LayoutInspector和Android的调试工具去各自分析了,如果打开LayoutInspector肉眼可见都是红色,赶紧改。
给首页的数据流增加页面级别缓存,让首页首刷不依赖接口返回就可以展示。
以上启动优化的点可以更详细的、更极致的优化,需要根据各自APP情况而定。
优化结果:
瓶颈是什么?——APP加壳
如何突破瓶颈?——混淆+VMP
在线上优化工作开展完成且取得了相应成果后,绝对不能放松警惕。
优化一次获得的效果并不是最重要的,最重要的是要有持续的、稳定的优化效果。
对于线上用户来说,其实可能并不关心这个版本或者这几个版本是不是变快了,大家可能更需要的是长时间的良好体验。
对于我们这些开发者来说,长时间的良好体验可能才能改变大家对自家 App 的性能印象,让大家认可自家 App 的启动性能,这也是我们优化的初衷。
因此,防劣化和优化同样重要。