爱奇艺APP Android低端机性能优化

01

   背景介绍

在智能手机市场上,高端机型经常备受瞩目,但低端机型亦占据了不可忽视的份额。众多厂商为满足低端市场的需求,不断推出低配系列手机。另外过去几年的中高端机型,随着系统硬件的快速迭代,现已经被归类为低端机型。爱奇艺APP拥有庞大的用户基群,其中低端机型用户也占据了相当一部分。低端机优化能给这部分用户带来稳定、流畅、高效的使用体验。下面将从冷启动、流畅性、加载速度三个维度介绍爱奇艺APP对低端机的优化策略。

低端机分级策略

介绍优化之前,我们看看低端机的标准,低端机设备的判断通常基于设备型号、内存大小和系统版本等因素。爱奇艺APP有自己的低端机分级策略,可在策略后台分场景(启动、流畅度等)、分等级(内存、机型、系统等)配置优化策略,以保障不同场景的最佳体验。

9bd1b3b1d1c310b1812ae5b05cd68f0a.png

02

   启动优化

启动是APP给用户打开的第一扇门,它的耗时长短直接影响用户后续的观感体验和留存,对业务指标有明显的影响。因此启动优化是技术优化方向的重点工作内容。

相关介绍

启动阶段的起点和终点:爱奇艺APP以 Application.attachBaseContext 为起点;以首页数据展现终点,该阶段经历的时长,作为线上正常冷启动耗时。这个主要经历 Application 创建阶段,MainActivity创建显示阶段,广告,首页顶底导航数据加载及渲染,首页数据加载及渲染这几个阶段。

186dada4226081418e032cb27f0801e3.jpeg

在这个过程中,要梳理出业务层做了哪些工作,评估其执行的必要性和执行时机以及所处调度线程的合理性;要监测主线程状态,是否陷入长时间休眠;主线程消息/后台消息监测治理,是否有不符合预期的任务被触发;是否有充分利用系统资源,是否充分利用空闲时机做预加载等。

业务功能原子化:为将启动阶段的任务能够有序调度、合理分配资源,开发了一套对任务管理的框架TaskManager,将业务功能实现包装在自定义Task里面,拆分得足够细,并设定Task之间的执行依赖关系,预期被调度执行的线程,执行时机等,然后统一交由 TaskManager处理,这层任务管理是我们实施启动优化的基础。

75837205eabdc181a7084d8c50436bc2.png


优化实践

开屏首页合并

早期爱奇艺APP开屏和首页是两个activity,两个activity带来一些用户体验问题:开屏结束刚进首页时低端机卡顿明显,首页也没有立即展现,用户能看到首页数据和图片都有一个从无到有的加载过程。

开屏阶段大多数场景是有开屏广告的,将开屏和首页合并到一个activity,利用开屏广告阶段将首页放到开屏页面的下面加载,并且将首页数据和UI展现分离并行处理,最大利用该阶段,最终可达到开机屏结束时首页立即展现,低端机上卡顿也明显好转

首页的渲染给开屏广告也带来的一定的影响。广告倒计时显示不稳定、少数类型的广告效果不流畅。对此首页加载拆成很多步骤在广告的回调的触发解决,倒计时显示使用surfaceView渲染保障其稳定性。

5606f691459fd5e2559551182b0abf58.jpeg


任务调度优化

基于启动类型,编排启动阶段任务执行时序,提前,延后,或不执行,从而让用户尽早的看到目标页面。以下是爱奇艺针对低端机正常启动路径下,对任务做出的调整。

a82f3b78fe37d2a8c714972592ad6828.jpeg


解决锁竞争

native库加载锁竞争:C层库加载是有锁的,Java层开多线程加载Lib库,到C层后仍会顺行执行加载,这就会导致Java层线程阻塞等待。爱奇艺在Application阶段有Lib库加载的需要,并要在主线程等待其加载完成后调用相关的JNI方法;而又遇到播放模块针对外部拉起进播放页这种情况,有预加载播放相关Lib库的需要,这会导致主线程进入等待状态。可通过在启动阶段识别目标落地页,来决定是否执行播放相关的Lib库预加载,从而避开大部分正常启动进首页的用户卡顿。(测试机 红米K40,Android12系统)

41ea70b56fa5df30c54a4dacfa31ec32.jpeg

资源锁竞争:爱奇艺首页展现前,有别的模块在子线程预加载布局文件,导致 LayoutInfalter / ResourceManager / AssertsManager 层锁竞争激烈。将预加载布局的任务调度到首页展现后执行,并且限制预加载布局在同一个子线程里面执行,可以看到改进后锁冲突次数大大减少了,这样能让首页更快展现出来。

5575a7913508a1d9a0d705382958e44b.jpeg


Baseline Profiles

Baseline Profiles:Google在2022年推出Baseline Profiles,允许开发者在apk内置自定义的热点代码基准配置文件。在APP安装期间,系统通过配置文件提前预编译热点代码。可以略过运行时所包含代码路径的解译和即时编译步骤,提升首次启动代码执行速度。

Startup Profiles:启动配置文件是上述基准配置文件一个子集,使用启动配置文件可改进APK的DEX文件中的代码布局,从而进一步优化包含的类和方法。爱奇艺APP通过启动配置文件将启动阶段的代码构建到同一个DEX文件中。使用上述两个策略爱奇艺APP在部分机型上首次启动速度提升约10%。

2b90c95ada02991fc8d4c41796e39a5e.png



外链拉启优化

外链拉起也是一种重要启动方式,通常有H5、分享、第三方APP等方式拉起,与正常冷启的区分在于外链拉起的往往不是首页,是特定的目标页。爱奇艺最常见的场景是拉起播放页,如果我们提前(application阶段)识别落地页,可以针对该落地页调整任务优先级,外链拉起播放页我们提前识别出播放页将播放器相关的任务提前初始化。通过这一策略低端机上外链拉起开播提速约1.5秒。

22a206d22edd2eff59634f2fa89db5d2.jpeg

03

   流畅度优化

相关介绍

爱奇艺APP大部分页面都是基于自研的Card框架进行开发。Card框架是一种高度可复用的UI框架,在使用原生代码实现基础UI布局和业务逻辑的基础上,通过后端下发的CSS控制来控制基础容器样式,来达到页面区块整体的复用,以及针对内容样式动态微调。是我们双端(Android和IOS)实现页面整体复用和局部微调的一种解决方案。在基于这套框架的基础上对APP内页面流畅度进行优化,Card框架如下特点:

  • 复用度高:由控件构成内容区块(Block),由多个区块组成行;由多个行组合成Card,再由多个Card组合成整个列表页面。其中业务最小可复用单元为Block。

  • 动态性强:支持在后台配置CSS文件,动态修改某个UI的样式(文字的大小、颜色,圆角等等)。

50d10323efd616b9acab10b7cd5354c2.jpeg

优化实践

样式Native化

Card页面的动态性和复用性导致了UI在布局上复杂性。一种类型的Block需要兼容多种样式形态,例如一张图上的四个角落,需要预埋各种类型的角标逻辑,而角标类型又包括纯图、纯文、图+文、可选中等形态。实现各种样式会导致View个数多、嵌套层级深,使得某些页面在低端机上滑动不够流畅。

为了优化这一现状,筛选出一些业务形态稳定的Card,针对这类Card做样式固化,在布局上做了大量精简。使得上下滑动上带来了明显的帧率提升。例如瀑布流Card,我们将实现的View数量由40+减少到17个,布局层级从6层下降低到2层;在不同的低端机上,带来了10%到20%不等的滑动帧率提升

e70cf74ddf5b342cc41fc01f7a6b1d95.jpeg

View合并绘制

上述布局简化策略带来的提升效果是明显的,但由于业务形态多样化,使得一些必要的View无法删减。为了进一步减少View个数和层级,将常用的Block布局中多个view合并到一个自定义的View上,利用View的画布,绘制文本、图片、按钮等样式信息。此方法可以有效减少View个数和嵌套层级,但仍需处理每个元素点击事件和按压效果。低端机,此种策略可以带来约1~2fps的滑动帧率提升

72316ee7168c1924140a1bfd78a4364d.jpeg


预创建&异步加载

布局预创建:如上图介绍的三种样式的Card中,使用的都是block类型相同(上图下文)。我们将这些常用的、复用度高的Block布局,在启动阶段预加载到缓存池中,使得列表滑动中可以直接使用预创建的布局,从而减少UI绘制中的inflate时间。

布局异步创建:预创建对常用的布局效果是不错的,但不常用布局还是占据多数,这类布局在滚动过程使用AsyncLayoutInflater异步创建将要出现的布局,减少滚布局在UI线程的创建时间,同时也可以提升RecyclerView预取的效率。

RecyclerView预取:爱奇艺APP不少页面用嵌套的RecyclerView去做横滑滚动产品形态,这类形态的card大多数在一屏里会露出3-5个item,根据不同形态设置不同的预取数(setInitialPrefetchItemCount,默认是2)可以减少这类card露出时的卡顿。

主线程减少非UI任务执行:在滚动过程检测主线程上耗时,发现部分非绘制任务在主线程执行,UI线程解析JSON,建立数据库链接等放到异步任务执行。


冷启UI消息调度

低端机在冷启动的过程中,资源消耗会逐步达到一个峰值状态;存在大量的UI消息(需要在UI线程执行)和其他后台任务需要执行。通过拦截埋点分析,这阶段有4000多条消息(15秒内)需要在UI线程上执行。在低端机上这些消息执行的时间从1ms到150ms不等。执行这些消息时系统的UI渲染消息就会被延时执行,在低端机上用户在APP刚启动时面临滑动卡顿、点击响应慢等问题。

针对这一问题,我们的解决方案是拦截所有往UI线程发送的消息加入到自定义的消息队列中;再监测系统UI消息队列的是否空闲状态,空闲时从自定义队列取出消息重定向到系统UI消息队列执行;另外增加白名单机制针对部分高优的消息放行。针对异常有回退机制处理。

通过对UI消息调度,使得低端机在冷启阶段卡顿程度得到了明显的改善;通过对线上大数据监测,冻帧和掉帧数大幅度减少。冷启阶段提升帧率提升约8fps

4d8ca513b817c09507d1941dc2d4ebbc.jpeg


效果降级策略

低端机上通过对部分效果降级有效的减少特定场景下卡顿, 爱奇艺APP做了如下的降级策略。

动效降级:顶底导航动效降级到静态图、播控动效关闭、部分产品功能的动效简化处理等。

播放降级:滚动延时播放&部分场景不开播等策略。

ViewPager预加载降级:禁止左右Tab的预加载,减少了view绘制时间和内存开销。

图片降级:部分页面动图不播,图片使用565像素格式。


04

   加载速度优化

相关介绍

除了前述的启动优化外,我们还专注于优化一些重要页面,因为这些页面的用户访问频率极高,对它们的优化能够显著提升用户体验。举例来说,搜索是用户经常使用的功能之一,因此我们对搜索行为进行了精细化拆解,并对搜索的每个步骤都进行了优化处理。

21a42b81d7f697427da76ef4bca9a354.png

优化实践

预请求

通常,页面的渲染过程通常从Activity的onCreate方法开始。之后再发起网络请求以获取必要的数据。获取到具体的数据之后再进行页面的渲染,之前在搜索场景我们也是这样的流程。

那有没有可能提前获取到需要的数据呢?

其实用户在首页点击搜索框时,已经有了网络请求所需要的参数。那就完全可以在点击时,提前发起网络请求,网络请求与页面跳转并发进行,缩短了网络请求时间。如果机器性能越差,页面点击到onCreate方法的时间越长,优化的时间也越多。低端机验证减少耗时约200ms。

d13ca34f819389a6ff81267e0afc68f4.png


据分次下发

用户在进入页面时,仅会呈现首屏数据,而页面下方的数据则需待用户执行滑动操作方能显示。因此,我们优先确保首屏数据的展示,通过减少首次数据下发的大小,减少了数据获取、数据传输、数据解析所需的耗时。在首屏数据渲染完成后,我们会再次发起接口请求,确保用户在执行滑动操作时,也能够立即呈现后续数据。在首页、半播页、搜索等多个重点页面都采用该方案进行优化,比如在搜索场景使用该方案,验证减少约200ms。


预创建

布局预创建:在搜索中间页空闲时,我们针对复用程度很高的布局,提前将这些布局创建到缓存中,页面真正渲染时,直接使用预创建好的布局,避免了view进行inflate的时间。

Fragment 预创建:在搜索中间页空闲时,提前创建好结果页的Fragment容器,在结果页展示时就不用创建对应的容器,减少容器创建耗时。

2043d703847f411f6bf301c90149cc37.png



主线程优化

在页面加载时,希望尽可能是页面相关的主线程任务先执行,如果重要任务调度被抢占了,就会影响页面渲染效果。通过我们内部自研的Tracepeed工具,接管主线程的Looper.loop() ,可以发现主线程中耗时较大的任务。如果发现耗时较长的低优先级任务被先执行了,可以调整任务调度,让重要任务优先执行。

比如在搜索结果页加载过程中,图片加载是一个重要的任务。但在低端机上,发现某些情况下会有另外一个任务抢占主线程,导致图片加载耗时有时长达1s。针对这种场景,调整任务调度,让图片加载任务优先执行,耗时稳定到在100+ms。

79b345ab95fc0a3b1132bbcc0dc7c355.png

业务逻辑优化

针对不同的业务,我们也分析了具体的业务逻辑,对相关逻辑进行优化:

  • 空图优化:在选集加载时,某些场景,后端会下发一个空图片,而这个空图片也会进行加载,导致页面加载耗时增加,因此我们针对空图,限制不进行加载。

  • 高频逻辑优化:在进行优化时,高频方法是一个需要重点关注的点,优化一些常用的高频方法,各个页面耗时都可以得到优化。比如:在基础控件上的初始化上,避免无用方法的执行,减少了这类高频方法的耗时。

  • 耗时方法异步执行:在页面加载过程中,也会有一些优先级不那么高的业务逻辑,当发现这些逻辑后,可以通过异步框架去执行这些逻辑,从而减少页面加载耗时。


防劣化

经过持续不断的优化,页面加载耗时已达到稳定水平。然而,在不断进行的开发迭代过程中,我们注意到了一些耗时增加的情况。如何有效地防止这种劣化的发生呢?

通过在代码里面重点方法进行埋点,每天定时执行流水线任务,多次执行取平均值后。用可视化的方式可以发现页面加载的波动情况。如果出现了劣化,就可以通过任务对比,直观的发现两次任务耗时差异点在哪里,针对耗时差异点进行分析优化。

3604efce5efa68e9d3c73705b64ceefa.png

359dc4887fdbad62500abeb74b71fdc3.gif

05

  总结与展望

低端机优化包括很多方面,上述介绍的几个核心业务场景下的部分优化手段,优先处理关键性能问题,有效提升低端机的运行性能,其中需要用的工具分析、线上监控、衡量标准这里没有提及,这些也是性能优化的重要利器。Android碎片化严重,低端机优化任重而道远。后续我们继续精进打磨,寻找新的优化突破点,以技术创新为用户提供稳定流畅的使用体验,助力高质量增长。

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

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

相关文章

APP开发_开发一个入门的 H5 APP

1 开发环境的搭建与准备 1.1 安装 Android Studio 下载:首先,从谷歌的安卓开发者网站(https://developer.android.google.cn/studio/releases?hlzh-cn)下载Android Studio的安装包。在下载页面中,可以根据自己的操作…

智慧公厕是智慧城市建设中不可或缺的一部分

智慧城市的数字化转型正在取得显著成效,各项基础设施的建设也在迅速发展,其中智慧公厕成为了智慧城市体系中不可或缺的一部分。作为社会生活中必要的设施,公共厕所的信息化、数字化、智慧化升级转型能够实现全区域公共厕所管理的横向打通和纵…

asp.net core 网页接入微信扫码登录

创建微信开放平台账号&#xff0c;然后创建网页应用 获取appid和appsecret 前端使用的vue&#xff0c;安装插件vue-wxlogin 调用代码 <wxlogin :appid"appId" :scope"scope" :redirect_uri"redirect_uri"></wxlogin> <scri…

【数据结构】树与二叉树遍历算法的应用(求叶子节点个数、求树高、复制二叉树、创建二叉树、二叉树存放表达式、交换二叉树每个结点的左右孩子)

目录 求叶子节点个数、求树高、复制二叉树、创建二叉树、二叉树存放表达式、交换二叉树每个结点的左右孩子应用一&#xff1a;统计二叉树中叶子结点个数的算法写法一&#xff1a;使用静态变量写法二&#xff1a;传入 count 作为参数写法三&#xff1a;不使用额外变量 应用二&am…

Python学习从0到1 day25 第二阶段 SQL ② Python操作数据库

少年有梦&#xff0c;不应至于心动&#xff0c;更要付诸行动 —— 24.4.12 pymysql 除了使用图形化工具以外&#xff0c;我们也可以使用编程语言来执行SQL从而操作数据库 在Python中&#xff0c;使用第三方库&#xff1a;pymysql来完成对MySQl数据库的操作 安装 pip install py…

什么是面向对象思想?

面向对象不是一种技术&#xff0c;而是一种思想。它指导我们以什么形式组织代码&#xff0c;以什么思路解决问题。 面向对象编程&#xff0c;是一种通过对象方式&#xff0c;把现实世界映射到计算机世界的编程方法。 面向对象解决问题的思路&#xff1a;把构成问题的事物分解成…

Go——网络编程

一. 互联网协议介绍 网络基础——网络传输基本流程_网络传输过程-CSDN博客 应用层HTTP协议-CSDN博客 传输层UDP/TCP协议_udp报文提供的确认号用于接收方跟发送方确认-CSDN博客 网络层IP协议-CSDN博客 链路层以太网详解_以太网数据链路层-CSDN博客 二. Socket编程 Socket是…

中国省级人口结构数据集(2002-2022年)

01、数据简介 人口结构数据不仅反映了地域特色&#xff0c;更是预测地区未来发展趋势的重要工具。在这些数据中&#xff0c;总抚养比、少年儿童抚养比和老年人口抚养比是三大核心指标。 少儿抚养比0-14周岁人口数/15-64周岁人口数 老年抚养比65周岁及以上人口数/15-64周岁人…

SpringBoot编写一个SpringTask定时任务的方法

1&#xff0c;在启动类上添加注解 EnableScheduling//开启定时任务调度 2&#xff0c; 任务&#xff08;方法&#xff09;上也要添加注解&#xff1a; Scheduled(cron " 0 * * * * ? ") //每分钟执行一次 域&#xff1a; 秒 分 时 日 月 周 &#xff08;年&#…

03-JAVA设计模式-外观模式

外观模式 什么是外观模式 外观模式&#xff08;Facade Pattern&#xff09;是面向对象设计模式中的一种&#xff0c;它为子系统中的一组接口提供了一个统一的高级接口&#xff0c;使得子系统更容易使用。外观模式定义了一个高层接口&#xff0c;让子系统更容易使用。子系统中…

【JS进阶】第四天

JavaScript 进阶 - 第 4 天 深浅拷贝 浅拷贝 首先浅拷贝和深拷贝只针对引用类型&#xff0c;因为简单类型直接拷贝值了 浅拷贝&#xff1a;拷贝的是地址&#xff0c;只拷贝一层 常见方法&#xff1a; 拷贝对象&#xff1a;Object.assgin() / 展开运算符 {…obj} 拷贝对象…

Linux_ubuntu使用常见问题解决

文章目录 1.安装好了搜狗输入法却只能输出英文&#xff1a; 1.安装好了搜狗输入法却只能输出英文&#xff1a; 1.浏览器搜索搜狗输入法&#xff0c;下载好安装包 终端输入下列命令安装&#xff0c;找不到文件可以cd到该安装包的目录文件下&#xff1a; sudo dpkg -i sogoupin…

自定义vue-cli 实现预设模板项目

模板结构 主要包括四个部分&#xff1a; preset.jsonprompts.jsgenerator/index.jstemplate/ 项目最终结构 preset.json preset.json 中是一个包含创建新项目所需预定义选项和插件的 JSON 对象&#xff0c;让用户无需在命令提示中选择它们&#xff0c;简称预设&#xff1b;…

从 0 搭建公司Jenkins服务 Centos7

从 0 搭建公司Jenkins服务 Centos7 安装 (运维人员) 安装环境 配置DNS安装JDK17安装Jenkins安装Docker安装GIT安装Ansible启动Jenkins安装插件配置凭据配置共享库配置 (开发经理)使用 (开发、测试人员) 安装 (运维人员) 安装环境 配置DNS 新安装系统的服务器无法解析域名&a…

云计算重要概念之:虚拟机、网卡、交换机、路由器、防火墙

一、虚拟机 (Virtual Machine, VM) 1.主流的虚拟化软件&#xff1a; 虚拟化软件通过在单个物理硬件上创建和管理多个虚拟环境&#xff08;虚拟机&#xff09;&#xff0c;实现资源的高效利用、灵活部署、隔离安全以及便捷管理&#xff0c;是构建云计算和现代化数据中心的核心…

B端:弹窗的场景、类型、 选择策略串讲,让你的设计有理有据。

B端产品在什么情况下使用弹窗&#xff0c;弹窗又分为哪些类型&#xff0c;该如何选择合理的弹窗形式&#xff0c;很多小伙伴都是跟着感觉走&#xff0c;本文告诉你依据。 一、弹窗及其场景 在B端系统中&#xff0c;"B端"通常指的是面向企业&#xff08;Business&am…

VMware Workstation部署最新版OpenWrt 23.05.3

正文共&#xff1a;1456 字 51 图&#xff0c;预估阅读时间&#xff1a;2 分钟 我们之前介绍了如何在VMware Workstation上安装OpenWrt&#xff08;软路由是啥&#xff1f;OpenWrt又是啥&#xff1f;长啥样&#xff1f;在VMware装一个瞅瞅&#xff09;&#xff0c;也介绍了如何…

十分钟学懂Java并发

并发简介 我们学到的基本上都是有关顺序编程的知识&#xff0c;即程序中所有事物在任意时刻都只能执行一个步骤。 编程问题中相当大的一部分都可以通过使用顺序编程来解决。然而&#xff0c;对于某些问题&#xff0c;如果能够并发地执行程序中的多个部分&#xff0c;则会变得非…

lua学习笔记19(面相对象学习的一点总结)

print("*****************************面相对象总结*******************************") object{} --实例化方法 function object:new()local obj{}self.__indexselfsetmetatable(obj,self)return obj end-------------------------如何new一个对象 function object:…

1688商品详情接口技术深探:解锁电商数据新纪元,实现业务自动化飞跃

1688商品详情接口技术解析 一、引言 随着电子商务的快速发展&#xff0c;越来越多的企业开始关注如何利用API接口获取商品详情信息&#xff0c;以实现数据的自动化处理和业务的快速拓展。1688作为国内知名的B2B电商平台&#xff0c;其商品详情接口成为了众多企业关注的焦点。…