啊?还不会卡顿优化?面试官:说下简历中提到的优化/整理下早期自己做的优化

我正在参加「掘金·启航计划」
为了吸睛,我还真是无所不用其极,把能想到的标题都写上了,大家见怪不怪吧...

先来点废话
听说最近 Android 岗位变多了,你去面试了么?
面试官:你简历中提到了卡顿优化,做了哪些优化呢,展开说说。
:哦,脑子飞速闪过网上的文章,然后说内存泄漏、内存抖动、启动优化、布局优化、图片优化、网络优化...
面试官:细节呢,详细些。
:哦,啊,哈哈哈...\

文章初衷
网上优化文章很多,各种主题都有,每次看那些大牛文章都觉得好有道理,啊我会了,可实际应用到项目的时候又不知道从哪里下手...
咋的,说的是不是你?反正这真的就是我。所以想着把自己做的一些小优化分享出来,主题尽量明确,看后更易上手,让世界更美好「为以后的面试润色」...

先不引入 Matrix 等第三方库,本文宗旨:先从简单处入手,尽量主题明确

Android Profiler

子曰:“工欲善其事,必先利其器。居是邦也,事其大夫之贤者,友其士之仁者。”

如果你刚刚开始优化,那就别上来就扯 systrace 和 traceview「已被废弃」 了,先看看 Android Profiler 吧。看看它能做什么:

  • CPU 性能分析器有助于查出运行时性能问题。
  • 内存分析器有助于跟踪内存分配情况。
  • 网络性能分析器可监控网络流量使用情况。
  • 能耗性能分析器可跟踪能耗情况,这有助于分析电池电量消耗过快的问题。

内存泄漏

ps:如果熟练此段可略过。另外只涉及到 java 层,未涉及到 native 层泄漏。
几年前,提到内存泄漏,很多人都会想到 LeakCanary,上手简单,而且去面试的时候很多时候还会问 LeakCanary 实现原理 / 为什么不能在线上应用等等...
现在时代换了,官方直系血亲来了。
本文使用的Studio版本:Android Studio Giraffe | 2022.3.1 Beta 1

先说定位步骤

  • 创造泄漏环境:
    App 多点几个页面,复杂页面可执行多次进入/退出的操作,再回到App 首页;

  • 打开 Profiler 界面:

image.png

  • 点击如下绿框选中icon

image.png

  • 呈现如下图,内存问题排查需要进入到 memory 模块

image.png

  • 捕获堆转储「即选择绿框内容」,并点击record,会自动开始分析,等待即可

image.png

image.png

  • 自动停止后,会出现如下展示:

image.png

  • 选择绿框选项,会筛选出 activity/fragment 层级的内存泄漏

image.png

卡顿「掉帧/ANR」

适用场景:已知某个行为会触发卡顿,eg:点击到某个tab,进入某个页面

先说定位步骤

  • 进入Profiler,点击进入 CPU 模块

image.png

  • 选中第四个「Java/Kotlin Method Sample」,点击record

image.png

  • 自己点击stop后,等待生成文件,有需要可以右键保存为 trace 文件;双击 main 模块,点击具体分析 UI 线程做了啥大事。

image.png

看到上图其实已经大概意识到事情没这么简单了...为啥?看颜色:

  • 对系统 API 的调用显示为橙色;
  • 对应用自有方法的调用显示为绿色;
  • 对第三方 API(包括 Java 语言 API)的调用显示为蓝色

tip:调节下图绿框中的两个箭头位置也可以放大/缩小

image.png

接下来就是重点看绿色部分,看看自有方法为啥导致绿色长度这么明显。

解决的问题

下面列出来的,都是我通过上面的方式,解决的部分问题。
声明:以下数据均比生产环境的值要小...

1.PackageInfo 相关的问题

通过 CPU Profiler 可以看到下图

PackageInfo 相关信息造成卡顿.png

/**
 * App 通过 PackageManager 去获取应用信息,是卡顿操作,若多个地方调用应存储为常量
 */
val packageInfo: PackageInfo? by lazy { PackageUtils.getPackageInformation(App.context) }
val applicationInfo: ApplicationInfo? by lazy { packageInfo?.applicationInfo }
val packageName by lazy { packageInfo?.packageName }
val packageVersionCode by lazy { packageInfo?.versionCode }
val packageVersionName by lazy { packageInfo?.versionName }
val firstInstallTime by lazy { packageInfo?.firstInstallTime ?: 0L }
val lastUpdateTime by lazy { packageInfo?.lastUpdateTime ?: -1L }

2.Websocket 使用问题

如下图,发现 UI 线程里面有大量 GSON 解析的操作,再跟踪,发现 App 中对于 WebSocket 的数据接收和处理,基本上是 UI 线程,造成掉帧 or 卡顿 or ANR。其实也惭愧,这个问题竟然之前没注意...

image.png

对于我们的 App 来讲,更致命,因为场景主要是歌房,消息基本都是通过 ws 来处理的,里面有各种UI的频繁更新、各种动效、各种动画、歌曲演唱...
所以凭借这个优化了整个App 对于 ws 的使用,改完后经住了测试组的压测、发热/卡顿等都好了很多,具体方法思路在这里 Android性能优化实战 - 直播间场景

3.EmojiManager.renderEmoji 方法

image.png

4.图文混排

项目中应该都有这种形式,text+icon 这种,如果在 RecyclerView 中使用,那卡顿就比较明显了

image.png

5.骨架屏耗时

这是之前的业务需求,后来一跑太耗时,直接下掉了...

image.png

6.获取通知是否可用

业务中很多关于是否获取通知权限的判断,这种case 应该存为全局常量,必要情况再去重新获取值。

image.png

Profiler 部分小结

这里说的只是初步使用,还有更细节且更精准定位某个方法的方式,需要去继续探索了。不过虽是初步使用,但是在我公司的项目里解决了不少问题,大家也开始吧 ~ 在一些场景下用 Profiler 去定位卡顿是不方便的,所以有很多优秀的框架 Matrix、Booster、KOOM 等。

线程优化

这个主题很大,开始的话,时间也比较长,前期储备较多知识点,具体应用还要结合自己的项目,我在这里只是提一下主题。
这个文章可以让你上手,并且认识到所需要的知识点:AOP 面向切面编程, 字节码插桩, 自定义 Gradle Plugin + Transform + ASM「小白操作版」
这个文章可以让你了解的多一些:AOP / 面向切面编程 / 字节码插桩 / ASM / 字节码扫盲学习 / 解读版

最后说点

  • 上面关于 LeakCanary 的问题,不会的话去查一查吧,再深入的话会接触到 Matrix ,关于 Matrix 的记录我也写过,看这里Matrix-TraceCanary 实际使用
  • 本文重点是在整理,提到的东西不新,但是比较经典。
  • 整理这个过程挺好的,过程中会锻炼自己的总结概括能力,仔细审视自己提及到的知识点是否正确,所以你也开始吧。
  • 知识体系非常重要,零散接受知识点的话比较被动,所以学习过程中就需要整理自己的知识体系,这样面试的时候就可以从点到面展开了「我假设的」。
  • 多看 Android 官方文档,看 Android 官方文档提到的项目,比如你想系统学习最近很火的 MVI/Compose。
  • 身处旋涡,就再挣扎一下。
  • 其实这些乱七八糟的写的不是我本意,但是逼着自己写一下。为什么我会这么费尽心思的想写点啥? 因为掘金姐告诉我了,只要我好好写,就给我一个证书,然后我就想用那个证书发个朋友圈... 你会帮我点赞的对么?

参考链接

官方文档-分析应用性能
官方文档-查看应用的内存使用情况

猜你喜欢

转载自juejin.im/post/7248183510234497084