Android 性能优化:存量App调优 + 新建App规范体系

整体思路:存量App:先观测定位,再分模块治理,最后建立监控防回退;新建App:架构、编码、编译、基线监控提前预埋,从源头避免性能坑

性能维度覆盖:启动、UI流畅度、内存、包体积、网络、耗电、IO,下面分开讲。


一、拿到一个已有应用,性能优化完整流程

阶段1:摸底 + 建立基线(最重要,不要上来直接改代码)

目标:拿到客观指标,区分「必改严重问题」和「优化锦上添花」,避免盲调。

  1. 确定性能指标基线
指标 工具 采集内容
启动耗时 Android Studio Profiler / ADB 冷启动命令 冷启动、温启动、热启动;adb shell am start -W 包名/Activity
帧率、卡顿 Perfetto / Choreographer 埋点 / BlockCanary 主线程卡顿、掉帧、ANR、长耗时方法
内存 Profiler、LeakCanary、MAT 内存抖动、内存泄漏、峰值内存、OOM场景
包体积 Android Studio Analyzer dex、资源、so、assets占比
耗电 Battery Historian WakeLock、后台唤醒、频繁传感器、网络
IO Perfetto 主线程磁盘读写、数据库慢查询
网络 Charles/OkHttpInterceptor 重复请求、大报文、串行请求
  1. 梳理问题清单,分级
    • P0(阻塞上线,优先修复):ANR、OOM、频繁崩溃、冷启动巨慢、页面严重卡顿
    • P1(体验明显变差):内存持续上涨、页面间歇性掉帧、后台耗电高、包体积过大
    • P2(体验微调):轻微内存抖动、非核心页面小幅掉帧
  2. 梳理App架构现状
    • 页面栈、组件:Activity/Fragment/Compose、多进程?
    • 网络库、图片库、数据库、路由、埋点、第三方SDK清单(很多性能问题来自第三方SDK)
    • 图片加载、对象创建、主线程任务、资源加载逻辑

阶段2:分模块定位+修复(按收益优先级)

1)启动优化(收益最高)

  • 区分冷/温/热启动,Application 是重灾区
    • 禁止在 onCreate 主线程做重任务:初始化SDK、数据库、解析大配置、加载大图
    • 懒加载:非核心SDK延迟初始化,放到首屏渲染完成后(IdleHandler)
    • 多进程:区分主进程和其他进程初始化,避免所有进程全量初始化
    • 避免静态成员大量初始化,静态对象持有大资源
  • Activity/Fragment:onCreate/onStart减少耗时,减少inflate嵌套,延迟非必要View创建
  • 编译:R8/Proguard开启,资源压缩,dex分包

2)UI & 卡顿优化

核心原则:主线程只做UI相关,任何耗时都丢到子线程

  • 传统XML:减少布局层级,避免过度绘制;使用ViewStub懒加载;减少invalidate频繁调用;避免在onDraw创建对象(内存抖动)
  • Compose:
    • 合理使用remember、derivedStateOf,避免不必要重组
    • 不要把宽高、状态直接在顶层传入,尽量缩小重组范围;稳定key(key{})处理列表
    • 避免Modifier顺序踩坑(background/padding/clickable顺序影响绘制和点击区域)
  • 卡顿监控:接入BlockCanary,捕获主线程阻塞堆栈;Perfetto抓取完整trace定位长耗时函数

3)内存优化

  1. 泄漏:LeakCanary自动捕获,重点排查:静态引用持有Activity、匿名内部类、Handler消息、异步回调、注册监听未反注册
  2. 内存抖动:循环内创建对象(字符串、集合、Bitmap),onDraw新建对象;用对象池、复用数组
  3. Bitmap:复用内存池,合理inSampleSize,避免大图一次性加载;Compose图片使用rememberAsyncImagePainter控制尺寸
  4. 集合:及时释放大集合,避免长生命周期对象持有大图/大列表数据

4)包体积优化

  • 资源:webp压缩图片,删除无用资源 shrinkResources;资源混淆;只保留对应ABI的so
  • Dex:R8开启代码压缩混淆,移除无用代码;动态功能模块(Dynamic Feature Module)拆分非核心业务
  • 清理冗余SDK,替换重SDK为轻量版本

5)网络 & IO & 耗电

  • 网络:请求合并、预取/懒加载、缓存策略;避免短时间大量请求;复用OkHttp连接池
  • IO:数据库用事务,主线程禁止读写SP/文件;SP不要存大数据;推荐DataStore替代SP
  • 耗电:控制WakeLock;减少频繁GPS、蓝牙;批量上报埋点,不要高频单点上报

阶段3:验证 + 建立持续防护(防止优化后回退)

  1. 回归复测:对比优化前后基线指标,确认指标改善,不能只靠肉眼感受
  2. 接入线上监控:
    • 性能埋点:冷启动耗时、页面FPS、ANR、OOM、内存峰值
    • 性能告警:指标超过阈值告警(例如冷启动>2s触发告警)
  3. 提交代码增加CR性能检查项,定期回归性能基线

存量App优化一句话总结:先抓数据定基线 → 优先解决P0问题 → 逐个模块治理 → 线上埋点监控,防止性能退化


二、全新开发App:必备配置 & 代码规范(从项目初始化就预埋性能能力)

1. 项目编译&Gradle基础配置(build.gradle)

android {
    // 开启代码压缩、资源压缩
    buildTypes {
        release {
            minifyEnabled true          // R8代码压缩混淆
            shrinkResources true        // 移除未使用资源
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    // 资源命名规范,便于后续资源瘦身
    resourcePrefix "app_"
    // 开启ViewBinding(XML项目),避免findViewById,减少空指针
    viewBinding.enabled true
}
  • 推荐:使用Kotlin + Jetpack Compose技术栈;架构选择 MVVM / MVI,单向数据流
  • 依赖版本统一管理:版本目录 version catalog,避免多依赖版本冲突,减少冗余代码

2. 架构层规范(防性能问题的顶层约束)

  1. 分层隔离:UI层(Activity/Compose)、ViewModel、Repository、DataSource;网络/DB放在下层,UI层不直接操作IO/网络
  2. 异步规范:
    • 优先Kotlin协程,禁止裸用Thread;使用CoroutineScope,页面销毁时cancel,防止泄漏
    • 网络/数据库/文件IO一律子线程;SP大数据迁移DataStore
  3. 组件规范
    • 尽量单Activity + 多Fragment / Compose Navigation,减少Activity创建销毁开销
    • 路由:ARouter,按需懒加载模块;不要一次性初始化所有路由目标
    • 多进程:谨慎使用;多进程之间资源独立,初始化代码做好进程判断,避免重复初始化

3. UI编码规范(XML / Compose)

XML

  • 布局扁平化,优先ConstraintLayout;减少嵌套LinearLayout
  • 懒加载:ViewStub处理非首屏视图;<include>复用布局
  • 图片:统一图片加载库(Coil/Glide),禁止直接BitmapFactory.decode在主线程加载大图
  • 禁止在onDraw、onLayout中创建对象

Compose 强制规范

  1. 可组合函数遵守:无副作用、参数稳定;@Stable标记数据类
  2. 状态提升,缩小重组范围;列表使用LazyColumn/LazyRow,不要ScrollColumn加载大量数据
  3. 列表Item提供稳定key:items(..., key={it.id})
  4. remember只用来缓存昂贵创建对象;derivedStateOf用于派生状态,避免不必要重组
  5. Modifier顺序规范理解:padding -> background -> clickable 顺序带来绘制区域差异

4. 内存相关编码规范

  1. 异步回调、监听注册必须成对反注册;协程作用域页面销毁cancel
  2. 禁止静态变量持有Activity/Fragment/View/Compose Context;Context使用Application上下文(非UI场景)
  3. 图片:统一限制采样尺寸,图片内存池;大图分页加载
  4. 集合:用完清空,避免长生命周期持有大列表;慎用全局静态大集合

5. 启动规范(新建项目最容易踩坑)

  1. Application 尽量轻量化,只放最基础初始化;所有非核心SDK放到IdleHandler / 首屏渲染后
Looper.myQueue().addIdleHandler(object : MessageQueue.IdleHandler {
    override fun queueIdle(): Boolean {
        // 首屏空闲后初始化非核心SDK
        return false
    }
})
  1. 区分主进程/其他进程初始化,用Process.myPid()判断
  2. 禁止在静态代码块做耗时任务

6. 预埋性能监控(新项目直接集成)

  • 开发阶段:LeakCanary(debug)、BlockCanary(debug)
  • 线上:性能SDK埋点(启动耗时、页面帧率、ANR、内存、崩溃)
  • 单元测试/自动化:可以编写自动化性能用例,CI打包时检测包体积、启动耗时,超过阈值阻断MR

7. 第三方SDK管理规范

  • SDK引入前评估:体积、内存、后台唤醒、WakeLock、线程创建情况
  • 非核心SDK支持按需懒加载;不要全部在Application初始化
  • 定期审计SDK,移除无用依赖

8. 数据库 & 网络规范

  • Room数据库,使用协程挂起函数;批量操作用事务;索引优化;避免查询全表
  • 网络:OkHttp单例,连接池复用;统一拦截器处理缓存、重试;批量埋点上报,不要高频单点上报

9. 代码检查静态工具(CI集成)

  • Lint:开启,自定义性能相关lint规则(主线程IO、主线程Bitmap加载等)
  • Detekt:Kotlin代码静态检查,捕获协程泄漏、不合理作用域
  • 提交MR强制Lint检查,不通过禁止合入

三、面试精简版(方便背诵)

存量App优化流程

  1. 采集性能基线(启动、卡顿、内存、包体积),定位P0/P1问题
  2. 优先解决启动、ANR、OOM这类高优先级问题;使用Perfetto、BlockCanary、LeakCanary、MAT定位
  3. 分模块优化:启动懒加载、主线程减负、内存泄漏&抖动、布局/Compose重组优化、包体积瘦身、网络IO耗电优化
  4. 回归验证,接入线上监控,建立性能门禁防止退化

新项目必备配置&规范

  1. Gradle开启R8、资源压缩,版本目录管理依赖
  2. 架构:MVVM/MVI + 分层,Kotlin协程管理异步,页面销毁取消任务防泄漏
  3. UI:XML扁平化;Compose遵守稳定状态、Lazy列表、remember/derivedStateOf规范
  4. Application轻量化,非核心能力懒加载,区分进程初始化
  5. 预埋监控LeakCanary、BlockCanary,CI增加Lint/Detekt、性能基线门禁
  6. SDK按需引入,IO/网络统一下层,禁止主线程耗时操作
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容