Android 性能优化(六):启动优化的详细流程


书接上文,Android 性能优化(一):闪退、卡顿、耗电、APK

从用户体验角度有四个性能优化方向:

  1. 追求稳定,防止崩溃
  2. 追求流畅,防止卡顿
  3. 追求续航,防止耗损
  4. 追求精简,防止臃肿

防止卡顿

卡顿的场景通常与用户交互体验最直接,分别为UI、启动、跳转、响应四个方面,如下图所示。

 主要有两大因素:

  • 界面绘制:层级深、元素复杂、频繁刷新等。由于这些原因导致卡顿的场景更多出现在启动后的初始界面以及跳转到页面的绘制上。
  • 数据处理:数据处理量太大。一般分为三种情况,一是数据在处理 UI 线程,二是数据处理占用 CPU 高,导致主线程拿不到时间片,三是内存增加导致 GC 频繁,从而引起卡顿。


UI优化

主要是绘制和刷新的卡顿,典型表现在页面的列表的滑动加载和刷新。

针对绘制可以使用懒加载,针对刷新可以使用局部刷新。详情参考:

(四)RecycleView 滑动到置顶、Adapter局部刷新

(七)RecycleView 性能提升、卡顿优化


启动优化

启动速度是用户第一印象,过长会让用户失去耐心; 根据行业数据统计,启动速度用户留存有着直接相关;对于开发者来说,通过各种技术手段来提升启动性能缩减启动时长,对整站业务的各项指标提升都会有较大帮助。因此,启动优化是各个客户端团队在体验优化方向上十分重要的一环。

评估量化

在计划优化立项之前,先确定两件事。

一、目标任务的启动是否值得优化?

衡量一个任务是否要启动有两个关键指标:“投入产出比”、“产出风险比”

  • 投入产出比:当完成优化任务需要 3人/天,收获90分位 100ms 的优化产出;另一个只收获90分位 10ms 的优化产出。显而易见选前者。因为优化的前期追求的的是优化收益,等到后续开启二期任务、三期任务需要做到更加极致时,才会考虑成本高但收益低的任务。
  • 产出风险比:当做优化任务时,可能会有风险点影响某个业务,这时需要衡量风险影响范围的大小,然后和业务方商讨劣化和优化的抉择,最后敲定任务排期。
二、优化的预期结果是否可量化?

有个比较简单的方法就是对标,比如,竞品App或主流App。

当然,启动优化最终目标是“秒开”,即需要 1s 内完成用户的启动流程。


量化建设

工作的价值就在于是否能建设丰富的数据大盘来明确以什么形式、从什么角度、监控什么指标。

启动优化的整体监控可以为:

  • 秒开率、2秒开率、3秒开率...
  • 90分位总体性能、90分位各阶段性能;(波动较小,不会被极端的case影响曲线)
  • 分版本各阶段各项指标、整体各阶段各项指标、主版本各阶段各项指标
  • 分场景,如有无广告等等
  • ...

耗时定义

业内常见的app启动过程阶段一般分为「启动阶段」和「首刷阶段」。

  • 启动阶段:指用户点击icon到见到app的首页,起点为ApplicationonCreate,终点ActivityonWindowFocusChanged()
  • 首刷阶段:指用户见到app的首页到首页列表内容展现起点为ActivityonCreate,终点列表的onAttachedToWindow() 。

为了确保启动优化量化指标的数据能稳定和完整。因此,排除其他启动场景的统计:

  • 启动过程中App退后台
  • 用户未登录场景
  • 特殊场景下的开屏广告,比如有复杂的联动动效
  • 站外push、deeplink拉起。

检测工具

Android Studio 自带的Profiler工具。

如果是 Android 10 及以上就用 Perfetto。


启动阶段

在App的启动流程中,有非常多的启动任务全部在Application的onCreate里被执行,有主线程的有非主线程的,但是不可避免的是,二者都会对启动的性能带来损耗。所以我们需要做的第一件重要的事情就是“启动任务重排与删减

可以把启动任务按优先级分类:

  • 刚需任务:这类任务初始化,根本无法进入后续流程。所以,不可延迟,必须第一时间最高优先级执行。比如网络库、存储库等基础库的初始化。
  • 非刚需高优任务:这类任务不初始化,不影响后续首页刷新,比如拉取ab实验配置、ip直连、push、长链接等基础建设项。这类任务没必要放在 UI 线程 block 执行,可以考虑放到启动阶段的后台IO线程中。
  • 非刚需低优任务:这类任务对启动阶段后续流程无决定性影响,可以放在启动阶段结束之后再后台执行。比如 x5内核、在线客服sdk、在线反馈SDK等。
  • 可删除任务:这类任务不需要存在于启动流程,在用到时再初始化。比如,登陆相关极验/深知SDK、定位相关城市json数据解析等

TaskManager任务管理器,大致代码参考如下:

TaskManager.getInstance().beginWith(A).then(B).then(C, D).then(E).enqueue();
TaskManager.getInstance().runAfterStartup({ xxx; })

通过任务的大致非精细化的排布,我们不仅仅可以对启动任务能够很好的进行监控,还可以更加容易的找出不合理项。

首刷阶段

从业务的角度出发,找到对启动流程影响最大的业务为切入点,尝试寻求更优的解法。

根据业务流程进行如下考虑:

  • IO 请求优先级提高,例如开屏广告接口请求提前发起。
  • IO wait期间,优化各项初始化,减少大量数据处理导致主线程拿不到时间片CPUTime。
  • 首页UI复杂度简化,列表的第一屏数据尽量走缓存。
1、 SplashActivity与MainActivity合并

当App启动时,会先进入SplashActivity等广告接口返回展示广告,然后转进MainActivity。这个流程对性影响最大的点是:等广告接口时,无法对后续业务做预加载,业务都在MainActivity。另外,启动阶段需要连续启动两个Activity,至少带来 百毫秒 级别的劣化。

合并前后,流程图如下: 

补充内容: 

MainActivity 作为launchAtivity的单实例问题。App从后台进前台,其他二级页面跳转到首页的依然走生命周期的现象。MainAcitvity 的 launchmode 需要设置为 singleTop。 

广告原先是以Activity的形式在展现,现在被抽离成 View 的形式去承载逻辑,在 onCreate 中,广告View添加进 DecorView中,完成对首页布局的遮罩。在广告View展示logo图时,底下首页框架是可以进行预加载的。

首页弹窗管理器需要延迟初始化。在广告View覆盖在上面时,先暂停弹层管理器的生命周期,避免出现其他内容盖住广告。

2、多Tab延迟加载+懒加载

首刷阶段的标志节点是在首页列表View的onAttachedToWindow()生命期中。因此,可以考虑其他Tab进行延迟加载和懒加载。即,如果用户不迫切切换Tab,就在首页View绘制时进行预加载;否则,就在用户点击Tab切换事件中进行加载(可能存在卡顿劣化,需作风险评估)。

3、布局优化

比如,广告View可以在接口返回数据且经过素材校验后,再进行布局的加载。类似的Banana位、搜索框、其他图片广告等。

  • 布局复用,使用<include>标签重用layout;
  • 提高显示速度,使用<ViewStub>延迟View加载;
  • 减少层级,使用<merge>标签替换父级布局;
  • 其他:使用wrap_content会增加measure计算成本;kotlin by lazy,动态内容加载的场景等。

4、绘制优化

过度绘制是指在屏幕上的某个像素在同一帧的时间内被绘制了多次。

在多层次重叠的 UI 结构中,如果不可见的 UI 也在做绘制的操作,就会导致某些像素区域被绘制了多次,从而浪费了多余的 CPU 以及 GPU 资源。

  • 移除 XML 中非必须的背景,移除 Window 默认的背景、按需显示占位背景图片;
  • 使用 canvas.clipRect() 识别可见区域,只在这个区域内才会被绘制。

可以通过LayoutInspector和Android的调试工具去各自分析了,如果打开LayoutInspector肉眼可见都是红色,赶紧改。。

5、page cache

给首页的数据流增加页面级别缓存,让首页首刷不依赖接口返回就可以展示。

以上启动优化的点可以更详细的、更极致的优化,需要根据各自APP情况而定。


阶段成果

优化结果:

  • 从2.87 降至最低时2.1,降幅26.8%
  • 再进行优化后效果不明显,遇到瓶颈 

优化瓶颈

瓶颈是什么?——APP加壳

  • APP加固中的加壳,严重拖慢了APP启动性能;
  • 且爱加密对加壳后的性能损耗无法优化;

如何突破瓶颈?——混淆+VMP

  • 壳的作用:对APPDex文件进行加密,防止APP被反编译,导致源代码泄露;
  • 替代方案: 对代码进行混淆,这也是行业通用做法 VMP加密,一种虚拟机加密技术,加密后将原有代码片段替换成新的片段,在执行时再解密;
  • 去壳需得到安全部门认可: 通过三方机构对加壳、仅混淆、混淆+VMP加密包进行安全测试; 得出结论为安全性 混淆+VMP > 仅混淆 > 仅加壳  

防劣化同样重要

在线上优化工作开展完成且取得了相应成果后,绝对不能放松警惕。

优化一次获得的效果并不是最重要的,最重要的是要有持续的、稳定的优化效果

对于线上用户来说,其实可能并不关心这个版本或者这几个版本是不是变快了,大家可能更需要的是长时间的良好体验。

对于我们这些开发者来说,长时间的良好体验可能才能改变大家对自家 App 的性能印象,让大家认可自家 App 的启动性能,这也是我们优化的初衷。

因此,防劣化和优化同样重要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/773846.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【IT之家】IT之家网站的资讯文章资源,实时数据抓取检索软件免费下载NO.65

简介&#xff1a;IT之家是业内领先的IT资讯和数码产品类网站。IT之家快速精选泛科技新闻&#xff0c;分享即时的IT业界动态和紧跟潮流的数码产品资讯&#xff0c;提供给力的PC和手机技术文章、丰富的系统应用美化资源&#xff0c;以及享不尽的智能阅读。 本软件基于C#实现的win…

苹果 WWDC 24 将举行;高通、谷歌、英特尔等联合开发 AI 软件;艺术家谈及使用 Sora 创作视频体验

▶ 苹果WWDC 24 将于当地时间 6 月 10 日召开 3 月 27 日凌晨&#xff0c;苹果官宣将于当地时间 6 月 10 日举行今年的全球开发者发布大会。 苹果全球营销高级副总裁 Greg Joswiak 在社交媒体上表示&#xff1a;「在您的日历标记上 WWDC24 吧。这场活动无疑会令人惊喜&#xf…

数字化转型核心:实现业务与技术深度融合的运维数字化管理之道

写在前面 数字化转型已经成为大势所趋&#xff0c;各行各业正朝着数字化方向转型&#xff0c;利用数字化转型方法论和前沿科学技术实现降本、提质、增效&#xff0c;从而提升竞争力。 数字化转型是一项长期工作&#xff0c;包含的要素非常丰富&#xff0c;如数字化转型顶层设…

Spring:面试八股

文章目录 参考Spring模块CoreContainerAOP 参考 JavaGuide Spring模块 CoreContainer Spring框架的核心模块&#xff0c;主要提供IoC依赖注入功能的支持。内含四个子模块&#xff1a; Core&#xff1a;基本的核心工具类。Beans&#xff1a;提供对bean的创建、配置、管理功能…

同城双活:交易链路的稳定性与可靠性探索

知易行难&#xff0c;双活过程中遇到了非常多的问题&#xff0c;但是回过头看很难完美的表述出来&#xff0c;之所以这么久才行文也是这个原因&#xff0c;总是希望可以尽可能的复现当时的思考、问题细节及解决方案&#xff0c;但是写出来才发现能给出的都是多次打磨、摸索之后…

阿里云安装宝塔后面板打不开

前言 按理来说装个宝塔面板应该很轻松的&#xff0c;我却装了2天&#xff0c;真挺恼火的&#xff0c;网上搜的教程基本上解决不掉我的问题点&#xff0c;问了阿里云和宝塔客服&#xff0c;弄了将近2天&#xff0c;才找出问题出在哪里&#xff0c;在此记录一下问题的处理。 服…

MySQL索引优化二

分页查询优化 很多时候我们的业务系统实现分页功能可能会用如下sql实现 select * from employees limit 10000,10;表示从表employees中取出从10001行开始的10条记录.看似只查询了10条记录,实际这条sql是先读取10010条记录,然后抛弃前10000条记录,然后读到后面10条想要的数据,…

Pillow教程07:调整图片的亮度+对比度+色彩+锐度

---------------Pillow教程集合--------------- Python项目18&#xff1a;使用Pillow模块&#xff0c;随机生成4位数的图片验证码 Python教程93&#xff1a;初识Pillow模块&#xff08;创建Image对象查看属性图片的保存与缩放&#xff09; Pillow教程02&#xff1a;图片的裁…

JVM本地方法

本地方法接口 NAtive Method就是一个java调用非java代码的接口 本地方法栈&#xff08;Native Method Statck&#xff09; Java虚拟机栈用于管理Java方法的调用&#xff0c;而本地方法栈用于管理本地方法的调用。 本地方法栈&#xff0c;也是线程私有的。 允许被实现成固定或…

【机器学习之---数学】统计学基础概念

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 统计学基础 1. 频率派 频率学派&#xff08;传统学派&#xff09;认为样本信息来自总体&#xff0c;通过对样本信息的研究可以合理地推断和估计总体信息…

Transformer 模型中增加一个 Token 对计算量的影响

Transformer 模型中增加一个 Token 对计算量的影响 Transformer 模型中增加一个 Token 对计算量的影响1. Transformer 模型简介2. Token 对计算量的影响3. 增加一个 Token 的计算量估算4. 应对策略5. 结论 Transformer 模型中增加一个 Token 对计算量的影响 Transformer 模型作…

【无标题】C高级325

练习1&#xff1a;输入一个数&#xff0c;实现倒叙123-》321 练习2&#xff1a;输入一个&#xff0c;判断是否是素数 练习3&#xff1a;输入一个文件名&#xff0c; 判断是否在家目录下存在, 如果是一个目录&#xff0c;则直接输出是目录下的sh文件的个数 如果存在则判断是否是…

ELF 1技术贴|应用层更改引脚复用的方法

在嵌入式系统设计中&#xff0c;引脚复用功能通常是通过设备树(Device Tree)预先配置设定的。出厂的设备树中UART2_TX_DATA和UART2_RX_DATA两个引脚被复用成了UART2功能&#xff0c;如果想要在不更换系统镜像的情况下&#xff0c;将这两个引脚的功能转换为GPIO&#xff0c;并作…

深入探讨iOS开发:从创建第一个iOS程序到纯代码实现全面解析

iOS开发作为移动应用开发的重要领域之一&#xff0c;对于开发人员具有重要意义。本文将深入探讨iOS开发的各个方面&#xff0c;从创建第一个iOS程序到纯代码实现iOS开发&#xff0c;带领读者全面了解iOS应用程序的开发流程和技术要点。 &#x1f4f1; 第一个iOS程序 在创建第…

基于springboot+vue+Mysql的超市进销存系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

工地污水处理一体化成套设备如何选型

工地污水处理一体化成套设备的选型是确保工地污水处理效果的关键。在选择合适的设备前&#xff0c;我们需要考虑几个重要因素。 首先&#xff0c;我们需要评估工地的实际污水处理需求。包括污水产生量、水质特征、处理要求等。通过了解工地的情况&#xff0c;我们能够确定适合处…

《探索移动开发的未来之路》

移动开发作为当今科技领域中最为炙手可热的领域之一&#xff0c;正以惊人的速度不断迭代和发展。从技术进展到应用案例&#xff0c;再到面临的挑战与机遇以及未来的趋势&#xff0c;移动开发都呈现出了令人瞩目的发展前景。本文将围绕移动开发的技术进展、行业应用案例、面临的…

服务运营 | 印第安纳大学翟成成:改变生活的水井选址

编者按&#xff1a; 作者于2023年4月在“Production and Operations Management”上发表的“Improving drinking water access and equity in rural Sub-Saharan Africa”探讨了欠发达地区水资源供应中的可达性和公平性问题。作者于2020年1月去往非洲埃塞俄比亚提格雷地区进行…

2.9 Python缩进规则(包含快捷键)

Python缩进规则&#xff08;包含快捷键&#xff09; 和其它程序设计语言&#xff08;如 Java、C 语言&#xff09;采用大括号“{}”分隔代码块不同&#xff0c;Python采用代码缩进和冒号&#xff08; : &#xff09;来区分代码块之间的层次。 在 Python 中&#xff0c;对于类…

【Java面试题】计算机网络

文章目录 1.计算机网络基础1.1网络分层模型/OSI七层模型是什么&#xff1f;1.2TCP/IP四层模型是什么&#xff1f;每一层的作用&#xff1f;1.2.1TCP四层模型&#xff1f;1.2.2为什么网络要分层&#xff1f; 1.2常见网络协议1.2.1应用层常见的协议1.2.2网络层常见的协议 2.HTTP2…