Android App 启动优化全记录

闲时调用


IdleHandler:当 Handler 空闲的时候才会被调用,如果返回 true, 则会一直执行,如果返回 false,执行完一次后就会被移除消息队列。比如,我们可以将从服务器获取推送 Token 的任务放在延迟 IdleHandler 中执行,或者把一些不重要的 View 的加载放到 IdleHandler 中执行

类加载优化


可以在 systrace 生成的文件中看到 verifyClass 过程,因为需要校验方法的每一个指令,所以是一个比较耗时的操作。

App 瘦身


App 瘦身包括代码瘦身和资源瘦身,通常的做法如下:

  • Inspect Code :Android Studio 提供的代码审查工具,实际上是内嵌了 Lint

  • 代码混淆

  • 图片格式的选择:如果对图片的要求不高,可以换成 565

  • 接入资源混淆

  • 减少 Dex 数量

选择合适的启动框架


启动优化整个流程的梳理,流程的梳理,我们这里引入了一个有向无环图的概念,我们会把整个的概念梳理成有向无环图的结构,然后会去挨个加载。右边的部分,可以看到我们其实在启动的时候,首先会去加载一些必要的启动项,必要的启动项是左边流程,会用一个多进程的方式加载,以来有向无环图进行控制,比如说我是在非必须的时候启动加载我可以放在后面再去加载。当然在整个有向无环图的顺序加载,其实还是会做一些进程的判断,要判断某些项目是不是要在主进程里加载,某些要在初始进程里面加载

从 Spark 的 DAGScheduler 中领悟到它的核心思想,面向阶段调度(Stage-Oriented Scheduler):把应用划分成一个个的阶段(Stage),再把任务(Task)安排到各个阶段中去,任务的编排则是通过构建 有向无环图(DAG),把任务依赖通过图的方式梳理得 井井有条。因为它分阶段执行,先集中资源把阶段一搞定,再齐心协力去执行阶段二,这样即能控制拥塞,又能保证时序,还能并发执行,让设备性能尽可能得到发挥

[图片上传失败…(image-6f2fdf-1574833214431)]

大家可以参考淘宝的全链路优化的案例:历时1年,上百万行代码!首次揭秘手淘全链路性能优化(上)

启动网络链路优化


问题和优化点

  • 发送处理阶段:网络库bindService影响前x个请求,图片并发限制图片库线程排队

  • 网络耗时:部分请求响应size大,包括 SO文件,Cache资源,图片原图大尺寸等

  • 返回处理:个别数据网关请求json串复杂解析严重耗时(3s),且历史线程排队设计不合适

  • 上屏阻塞:回调UI线程被阻,反映主线程卡顿严重。高端机达1s,低端机恶化达3s以上

  • 回调阻塞:部分业务回调执行耗时,阻塞主线程或回调线程

优化

  • 多次重复的请求,业务方务必收敛请求次数,减少非必须请求。

  • 数据大的请求如资源文件、so文件,非启动必须统一延后或取消。

  • 业务方回调执行阻塞主线程耗时过长整改。我们知道,肉眼可见流畅运行,需要运行60帧/秒, 意味着每帧的处理时间不超过16ms。针对主线程执行回调超过16ms的业务方,推动主线程执行优化。

  • 协议json串过于复杂导致解析耗时严重,网络并发线程数有限,解析耗时过长意味着请求长时间占用MTOP线程影响其他关键请求执行。推动业务方handler注入使用自己的线程解析或简化json串。

预加载


Activity 打开之前就预加载数据,在 Activity 的 UI 布局初始化完成后显示预加载的数据,大大缩短启动时间。 可以参考 :https://github.com/luckybilly/PreLoader/blob/master/README-zh-CN.md

保活


保活,是各个应用开发者的噩梦,也是 Android 厂商关注和打击的重点。不过从启动的角度来看,如果应用进程不被杀,那么启动自然就快了,所以保活对应用启动速度也是有极大的帮助。

当然这里说的保活,并不是建议大家用各种黑科技、相互唤醒、通知轰炸这种保活手段,而是提供真正的功能,能让用户觉得你在后台是合理的、可以接收的。比如在后台的时候,资源能释放的都释放掉,不要一直在后台做耗电操作,该停的服务停掉,该关的动画关掉。

当然对于应用开发者来说,上面说的都太多理想化了,而且目前的手机厂商也会很暴力,应用到了后台就会处理掉,不过这毕竟是一个方向,Google 也在规范应用后台行为和规范厂商处理应用这两方面都在做努力,Android 系统的生态,还是需要应用开发者和 Android 厂商一起取改善。

当然保活还有一条路就是走跟厂商的合作,优化后台内存、去掉重复拉起、去掉流氓逻辑、积极响应低内存警告,做好这些话后可以跟系统厂商联系,谈放到查杀白名单和自启动白名单的可行性

业务梳理


这里涉及到具体的业务,每个 App 都不一样,但是所要做的事情都是一样的,下面是邵文在高手课里面提到的:

  • 梳理清楚启动过程中的每一个模块,哪些是一定需要的,那些是可以砍掉,那些是可以懒加载的

  • 根据不同的业务场景决定不同的启动模式

  • 懒加载防止集中化

可以把具体的业务分为下面四个维度(此处图文来自https://juejin.im/post/5c21ea325188254eaa5c45b1#heading-5

  • 必要且耗时:启动初始化,考虑用线程来初始化

  • 必要不耗时:首页绘制

  • 非必要但耗时:数据上报、插件初始化

  • 非必要不耗时:不用想,这块直接去掉,在需要用的时再加载

然后按需进行加载优化

业务优化


  1. 优化业务中的代码效率,抓大放小,先从比较明显的瓶颈处下手,逐步进行优化

  2. 历史债务要偿还,历史的代码要重构,不能一直拖着

具体的业务会有具体的优化场景,大家可以参考这篇文章中的优化流程和优化项(https://www.jianshu.com/p/f5514b1a826c)

  1. 数据库及IO操作都移到工作线程,并且设置线程优先级为THREAD_PRIORITY_BACKGROUND,这样工作线程最多能获取到10%的时间片,优先保证主线程执行
  1. 流程梳理,延后执行;实际上,这一步对项目启动加速最有效果。通过流程梳理发现部分流程调用时机偏失等, 例如
\*\* 1. 更新等操作无需在首屏尚未展示就调用,造成资源竞争  
\*\* 2. 调用了IOS为了规避审核而做的开关,造成网络请求密集  
\*\* 3. 自有统计在Application的调用里创建数量固定为5的线程池,造成资源竞争  
\*\* 4. 修改广告闪屏逻辑为下次生效
  1. 去掉用无但被执行的老代码
  1. 去掉开发阶段使用但线上被执行的代码
  1. 去掉重复逻辑执行代码
  1. 去掉调用三方SDK里或者Demo里的多余代码
  1. 信息缓存,常用信息只在第一次获取,之后从缓存中取
  1. 项目是多进程架构,只在主进程执行Application的onCreate()

减少Activity的跳转层次


StartingWindow 会在用户点击 App 后立即创建并显示(前提是 App 没有禁止 StartingWindow),在 AppWindow 创建好之后,StartingWindow 消失,AppWindow 显示

默认 App 的启动窗口流程

StartingWindow(SystemWindow)

->MainActivity(AppWindow)

大部分三方 App 启动流程

StartingWindow(SystemWindow)

-> SplashActivity(AppWindow)

-> MainActivity(AppWindow)

###糟糕一点的启动流程是这样的

StartingWindow(SystemWindow)

-> MainActivity(AppWindow)

-> SplashActivity(AppWindow)

-> MainActivity(AppWindow)

更糟糕一点的启动流程:去掉了 StartingWindow

SplashActivity(AppWindow)

-> MainActivity(AppWindow)

其实对用户来说,第一种启动流程是最好的,只涉及到一次窗口的切换;但是部分 App 由于广告页的需求,会使用第二种流程 ;但是尽量不要使用第三种和第四种启动流程,体验非常不好

厂商优化

================================================================================================================================================================================================

除了 App 自身的优化之外,Android 框架对应用启动也是非常关注的,做了比较多的优化,下面简单说一下思路,各个厂商的实现也不太一样,但是基本上都会有,有些是硬核代码优化,有的是利用系统策略做优化。

厂商的策略各不相同,这里只是简单的提一下思路

启动加速


App 启动的时候,系统会对要启动的应用做绝对的资源倾斜,比如 CPU、IO、GPU 等,这一点大家抓个 Systrace 看一下即可,不管是频率还是调度算法,正在启动的 App 绝对是当时的系统 VIP 客户

部分厂商也提供了资源调度的 SDK ,应用可以接入这些 SDK,在需要资源的时候直接调用 SDK 获取

PreFork


Android Q 加入了 PreFork 机制,会先 fork 几个空进程,当 App 启动的时候,可以直接复用这几个空进程,而不用重新去 fork

2,348K: usap32 (pid 18731)

2,346K: usap32 (pid 18702)

2,343K: usap32 (pid 18707)

2,342K: usap32 (pid 18729)

2,341K: usap32 (pid 18711)

2,335K: usap32 (pid 20322)

2,335K: usap32 (pid 20325)

2,333K: usap32 (pid 20319)

2,333K: usap32 (pid 20320)

2,333K: usap32 (pid 20321)

1,509K: usap64 (pid 21169)

1,509K: usap64 (pid 21180)

1,507K: usap64 (pid 21171)

1,452K: usap64 (pid 21513)

1,450K: usap64 (pid 21506)

1,449K: usap64 (pid 21512)

1,447K: usap64 (pid 21511)

1,445K: usap64 (pid 21514)

启动消息重排


启动的时候,对启动过程中的 Message 进行重新排列

主线程、渲染线程加速


部分厂家会对启动过程 App 的主线程和渲染线程做特殊对待,比如让他们直接跑到大核上,将其他不重要的线程移到小核

启动预测


部分场景会针对用户的使用习惯进行学习,比如在什么时间、什么场合、什么交通工具打开手机,系统会预测你要启动的 App,并在后台进行启动,这样你点击这个 App 的时候,就已经是热启动了

后台保活


系统也会对一些应用进行特殊处理,以提升用户体验:包括但不限于 进程\线程优先级调整、查杀白名单、用户常用应用记录等,进行适当的后台保活,下次启动的时候就是热启动了

后台重启


系统会对一些应用进行特殊处理,比如这个 App 比较重要但是不能杀掉,那么有的厂商会在这种应用退到后台之后,进行无感重启:比如说某个应用内存超标或者持续 Crash ,后台重启可以很好地解决这个问题,这样重启后的 App 是用户点击启动的时候就是热启动

内存优化


部分应用启动的时候,需要大量的内存,比如现在的相机启动,这时候如果没有足够的内存,那么系统必须要通过杀掉很多应用、释放 Cache 等操作来给这个 App 让路,这个过程会使得这些大内存的 App 在启动的时候频繁进行内存操作,导致启动速度变慢

部分厂商会在监测到这种大内存 App 启动的时候,提前做内存的回收操作,这样在启动的时候,就有了足够的内存给这个 App 使用

优化启动逻辑


Android 系统更新也会对应用启动速度进行优化,比如上面提到的 Pre-Fork,又比如这里的简化 doFrame 个数

如何做好面试突击,规划学习方向?

面试题集可以帮助你查漏补缺,有方向有针对性的学习,为之后进大厂做准备。但是如果你仅仅是看一遍,而不去学习和深究。那么这份面试题对你的帮助会很有限。最终还是要靠资深技术水平说话。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。建议先制定学习计划,根据学习计划把知识点关联起来,形成一个系统化的知识体系。

学习方向很容易规划,但是如果只通过碎片化的学习,对自己的提升是很慢的。

我们搜集整理过这几年字节跳动,以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。

img

我们在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

学习方向很容易规划,但是如果只通过碎片化的学习,对自己的提升是很慢的。

我们搜集整理过这几年字节跳动,以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。

[外链图片转存中…(img-AG2xSrDO-1714270228670)]

我们在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值