拼多多冷启真的秒开

2 阅读8分钟

可能是东半球最好的Android面试资料

视频版 内容更丰富体验更佳哦

B站链接 www.bilibili.com/video/BV1BA…

—————————————————阴阳割昏晓———————————————

背景

最近在使用拼多多购物,除了价格比较香之外,每次冷启打开的体验非常好,作为一个Android开发不免好奇 简单分析记录一下

冷启数据

体验好,让我想到了郭德纲的那句话"全靠同行的衬托",那找几个同行过来对比下,这里使用淘宝、京东、闲鱼,从点击开始图标开始录个屏直接数秒,

测试手机是 华为 Mate 60

我这个样本比较少,机器性能也比较好,仅仅是个人对比,不代表大众使用的真实情况

可以粗略的看几个常见app的冷启对比下,这里录屏使用的剪映来分析 帧率为 每秒30帧,后面会涉及一些时间换算 image.png

拼多多

无广告冷启动 从点击图标到到首页完整展示 大概花了 29帧, 1000ms * 29/30 约为 0.96s ,太惊人了,基本冷启秒开

拼多多可能真的没有开屏广告,我印象中没有见过拼多多的开屏广告

image.pngimage.png

淘宝

无广告冷启东 从点击图标到到首页完整展示 image.png image.png 大概花了 1s+21帧, 1000ms+ 21/30*1000ms = 1.7s 还可以

淘宝可能没有开屏广告,或者非常克制,我刷了十几次都没有见到开屏广告

京东

无广告冷启京东 从点击图标到到首页完整展示 image.png image.png

大概花了 1s+28帧, 1000ms + 28/30*1000ms 约为 1.93s 也是不错的

不过京东的开屏有开屏广告,但是做了用户频控,刷了几次就没了,这里仅对比无广告冷启开屏

闲鱼

毕竟是国内最大的二手平台(虽然现在小商家也特别多),而且是flutter深度使用者,看看它的表现 image.png image.png 大概花了** 2s+10帧** 2000ms+ 10/30*1000ms 约为 2.3s

image.png 从上面数据来看,怪不得 我使用拼多多之后,打开app 确实比较舒服,因为我就是奔着买东西去的,越快到购物页面越舒服的。或许这就是极致的用户体验吧

首屏细节

拼多多的首页数据咋这么快就准备好了,网络耗时应该也有呢,应该是它提前准备好了数据 image.png 我们来实操验证下

  • 切后台的截图

我们记住 手枪、去虾线、行李箱、停电 这几个卡片 image.png

冷启打开之后首先展示的是 还是切后台之前的数据 image.png 紧接着网络数据到了做了一次屏幕刷新 image.png

到这里大概就明白了,冷启使用上次feeds流的数据,先让用户看到数据,然后等新数据请求到之后再刷新页面就好

为了严谨点,把缓存数据清除的话,那么肯定首次冷启白屏,ok最后再验证一下 image.png

此时冷启白茫茫的一片,看来拼多多的策略还是让用户尽快进应用优先,或者这里并没有刻意设计🤔,都是先进首页有缓存就使用 没有的话就等网络数据,毕竟这种情况也只是新用户或者缓存数据过期才会这样 image.png

因此这里我可以得出把这种缓存优先的技术方案也可以学习学习,看看我们自己的app是不是可以复用一下,绩效这不就来了吗🤔 首页 = 数据 + UI 数据是使用缓存,UI也能吧一些UI组件提前预加载,不过这里也无法判断 是否预加载了首页UI🤔

开屏无广告

我目前在字节就是搞广告的,所以对广告稍微敏感些,开屏广告是一个很棒收入来源,特别是合约广告这种,之前应用冷启时间长,有时候其实是故意抽出一些时间来等待冷启的开屏广告, 但是我试了很多次,确实没看过拼多多的开屏广告,不过从这个结果来看 肯定是 经过严密的ab实验,不过拼多多在开屏广告上确实比较克制,

关于现在互联网的计算广告业务还是蛮有意思的比如 广告类型有 开屏、原生、激励、插屏、横幅,sdk类型有单个adn或者聚合广告sdk,有时间再单独分享几篇。

image.png

冷启优化一些常见手段

冷启动往往是大型应用的必争之地

  1. 实打实的提升用户体验
  2. 可能会带来一些GMV的转化

拼多多技术是应该是有些东西的,但是非常低调,属于人狠话不多那种,也没找到他们的方案。这里结合自身经验聊聊这块,主要是以下4个阶段结合技术手段做优化 image.png

Application attachBaseContext

这个阶段由于 Applicaiton Context 赋值等问题,一般不会有太多的业务代码,可能的耗时会在低版本机器4.x机器比较多,首次由于MultiDex.install耗时

dex 的指令格式设计并不完善,单个 dex 文件中引用的 Java 方法总数不能超过 65536 个,在方法数超过 65536 的情况下,将拆分成多个 dex。一般情况下 Dalvik 虚拟机只能执行经过优化后的 odex 文件,在 4.x 设备上为了提升应用安装速度,其在安装阶段仅会对应用的首个 dex 进行优化。对于非首个 dex 其会在首次运行调用 MultiDex.install 时进行优化,而这个优化是非常耗时的,这就造成了 4.x 设备上首次启动慢的问题。

可以使用一些开源方案,比如 github.com/bytedance/B… 不过 这里优化难度比较大,roi的话 看看app低版本的机型占比再做决定

ContentProvider

这里要注意检查 ContentProvider,特别是一些sdk在 AndroidManifest 里面注册了自己的 xxSDkProvider,然后在 xxSDkProvider 的 onCreate 方面里面进行初始化,确实调用者不需要自己初始化了,可却增加了启动耗时, 我们可以打开 Apk,看一下最终merge的 AndroidManiest 里面有多少 provider,看一下是否有这样的骚操作,往往这里容易忽视,这种情况可以使用谷歌App Startup来收敛ContentProvider

Application 优化

  1. 精简Application 中的启动任务
  2. 基于进程进行任务排布,比如常见的push进程、webview进程

西瓜视频 在冷启优化就将 push、小程序、sandboxed这几个进程做了优化拿到一些不错的收益mp.weixin.qq.com/s/v23jEhF9k…

搞进程难度大风险高

  1. 启动链路任务编排

这里需要先梳理启动链路,做成1任务编排,

  1. 比如之前串2.2行的,搞成并行初始化
  2. 核心任务做有向无环图(DGA)编排,非核心的延迟初始化

idlehandler是个好东西。 image.png image.png

关于初始化DGA框架有不少框架,谷歌官方也有个 App Startup,感兴趣可以研究下

首页优化

首页是用户感知到的第一个页面,也是冷启优化的关键,前面也提过 首页 = 数据 + UI

  1. 数据 可以使用缓存
  2. UI的话 通常是xml解析优化,或者预加载

在性能较差的手机上,xml inflate 的时间可能在 200 到 500 毫秒之间。自定义控件和较深的 UI 层级会加重这个解析耗时。 一些框架比如x2c,或者AsyncLayoutInflater 可以帮助我们在UI这里做做文章

  1. 插件化

把非核心模块做成插件,使用时候下载使用,一劳永逸,不过插件化也有各种弊端

后台任务优化

主线程相关耗时的优化,事实上除了主线程直接的耗时,后台任务的耗时也是会影响到我们的启动速度的,因为它们会抢占我们前台任务的 cpu、io 等资源,导致前台任务的执行时间变长,因此我们在优化前台耗时的同时也需要优化我们的后台任务

  1. 减少后台线程不必要的任务的执行,特别是一些重 CPU、IO 的任务;
  2. 对启动阶段线程数进行收敛,防止过多的并发任务抢占主线程资源,同时也可以避免频繁的线程间调度降低并发效率
  3. GC 抑制

触发 GC 后可能会抢占我们的 cpu 资源甚至导致我们的线程被挂起,如果启动过程中存在大量的 GC,那么我们的启动速度将会受到比较大的影响。通过hook手段在启动阶段去抑制部分类型的 GC,以达到减少 GC 的目的。这个就比较高端了,也是只在一些大厂文章里面见过。

OK 本期就到这里了