优化
优化方案
Android 性能优化是一个系统性工程,涉及 启动速度、UI 流畅度、内存占用、电量消耗、网络请求 等多个维度,最终目标是提升用户体验(如减少卡顿、降低耗电、加快响应)。以下从核心优化方向分类、优化手段、工具三个方面详细解析:
核心性能优化方向及优化手段
1. 启动速度优化
问题:冷点击图标后启动慢、黑屏 / 白屏时间长。
优化手段:
冷启动优化:
- 精简
Application初始化:避免在onCreate()中执行耗时操作(如网络请求、大量计算),非必要库延迟初始化(异步线程或Lazy加载)。 - 优化
Launcher Activity:onCreate()中只做必要的视图初始化,耗时逻辑(如数据加载)放到异步线程或onWindowFocusChanged()后。 - 减少布局层级:启动页布局尽量简单,避免过度绘制。
- 精简
利用启动主题:通过自定义
windowBackground替换黑白屏(见「黑白屏问题」优化),让用户感知更快。启动器工具:使用
Android Studio Profiler或Systrace分析启动耗时,定位瓶颈(如耗时方法、阻塞线程)。
2. UI 流畅度优化(减少卡顿)
问题:界面滑动卡顿、动画掉帧(正常应保持 60fps,即每帧耗时 <16ms)。
优化手段:
布局优化:
- 减少层级:使用
ConstraintLayout替代嵌套LinearLayout/RelativeLayout,避免过度嵌套(建议层级 ≤5 层)。 - 复用布局:通过
<include>复用公共布局,<merge>减少根节点冗余。 - 延迟加载:对非首屏视图用
ViewStub延迟加载(如列表项中的详情区域)。
- 减少层级:使用
绘制优化:
- 减少过度绘制(Overdraw):通过「开发者选项 → 调试 GPU 过度绘制」检测,移除无用背景(如父布局和子布局重复设置背景),避免重叠绘制。
- 优化自定义 View:
onDraw()中避免创建对象(如Paint应初始化一次)、减少复杂计算(如频繁调用measure),必要时用硬件加速(注意兼容问题)。
主线程优化:
- 避免主线程做耗时操作:网络请求、数据库读写、大文件处理等必须放子线程(用
Thread、AsyncTask、Coroutine或RxJava)。 - 控制主线程任务:通过
Handler延迟处理非紧急任务,避免短时间内大量任务阻塞主线程。
- 避免主线程做耗时操作:网络请求、数据库读写、大文件处理等必须放子线程(用
3. 内存优化(减少 OOM 和内存泄漏)
问题:内存占用过高导致 OOM(OutOfMemoryError)、频繁 GC 引起卡顿、内存泄漏导致内存无法释放。
优化手段:
减少内存占用:
- 图片优化:使用合适分辨率的图片(如
xxhdpi设备用xxhdpi资源),通过Glide/Picasso加载图片时压缩尺寸(override(width, height)),大图片用BitmapRegionDecoder分片加载。 - 避免不必要的对象创建:循环中不创建临时对象,复用
StringBuilder而非String拼接,使用基本数据类型(int)替代包装类(Integer)。 - 合理使用数据结构:如用
SparseArray替代HashMap存储键值对(int → Object),减少内存开销。
- 图片优化:使用合适分辨率的图片(如
避免内存泄漏:
- 生命周期管理:
Activity/Fragment中,避免静态变量持有其引用(如static Context mContext = this),使用WeakReference持有临时引用。 - 资源释放:
onDestroy()中取消网络请求(如OkHttp的Call.cancel())、移除监听器(Listener)、停止动画(ValueAnimator.cancel())、释放Bitmap(recycle())。 - 单例模式:确保单例不持有
Context或持有Application Context(而非Activity Context)。
- 生命周期管理:
监控内存:通过
Profiler观察内存波动,LeakCanary检测内存泄漏(自动 dump 泄漏路径)。
4. 网络优化
问题:网络请求慢、流量消耗大、弱网 / 离线场景体验差。
优化手段:
减少请求次数:
- 接口合并:将多个独立请求合并为一个(如首页数据一次性获取,而非分多次请求)。
- 数据缓存:通过
Retrofit + OkHttp配置缓存策略(CacheControl),缓存 GET 请求结果,减少重复请求。
减少数据量:
- 数据压缩:服务器返回 GZIP 压缩数据,客户端启用解压(OkHttp 自动支持)。
- 轻量化数据格式:用
Protocol Buffers替代 JSON(体积更小、解析更快),或 JSON 字段精简(只返回必要字段)。
弱网优化:
- 超时重试:设置合理的超时时间(如连接超时 5s,读取超时 10s),失败后有限次数重试(避免无限重试浪费流量)。
- 预加载与离线缓存:提前加载可能需要的数据(如用户进入首页前预加载列表),离线时展示缓存数据。
网络监控:使用
OkHttp Interceptor记录请求耗时、成功率,定位慢接口或失败原因。
5. 电量优化
问题:App 后台耗电快,用户频繁充电。
优化手段:
减少后台唤醒:
- 避免频繁
AlarmManager唤醒(如将多个定时任务合并,使用setExactAndAllowWhileIdle替代setRepeating)。 - 后台任务批量处理:用
WorkManager调度后台任务(如同步数据),设置在设备充电、WIFI 环境下执行,避免频繁唤醒 CPU。
- 避免频繁
优化网络请求:
- 减少后台网络请求:非必要的后台同步(如广告数据)延迟到前台执行,或限制频率(如每小时一次)。
- 批量请求:将零散的小请求合并为一个,减少无线电唤醒次数(移动网络唤醒耗电高)。
硬件使用优化:
- 及时释放传感器:使用 GPS、蓝牙等硬件后,在
onPause()中停止(如locationManager.removeUpdates(listener))。 - 减少 WakeLock 持有时间:必要时用
WakeLock保持屏幕 / CPU 唤醒,但使用后立即释放(避免忘记释放导致屏幕常亮)。
- 及时释放传感器:使用 GPS、蓝牙等硬件后,在
6. 安装包体积优化
问题:Apk 体积过大导致下载转化率低、安装慢。
优化手段:
资源优化:
- 图片压缩:用
WebP格式替代PNG/JPG(同等质量下体积小 30%+),通过Android Studio → Convert to WebP转换。 - 移除冗余资源:通过
Build → Analyze APK分析冗余文件,shrinkResources true自动移除未引用资源(需配合minifyEnabled true)。 - 资源混淆与压缩:使用
AndResGuard混淆资源文件名并压缩资源。
- 图片压缩:用
代码优化:
- 启用代码混淆:
minifyEnabled true配合ProGuard/R8移除未使用代码(Dead Code)、混淆类名,减少 dex 体积。 - 动态功能模块:通过
App Bundle(aab)将非核心功能(如插件、附加内容)做成动态模块,用户按需下载。
- 启用代码混淆:
第三方库精简:移除未使用的库,或用轻量级库替代(如用
LitePal替代GreenDAO,用OkHttp基础功能替代全套 Retrofit+RxJava)。
性能优化工具
- Android Studio 内置工具:
- Profiler:监控 CPU(定位耗时方法)、内存(检测泄漏、GC 频率)、网络(请求耗时、流量)、电量消耗。
- Systrace:分析系统级耗时(如帧渲染、线程调度),生成 HTML 报告定位卡顿原因(如
ALWAYS_RUNNING线程)。 - Lint:静态代码分析,检测布局冗余、未使用资源、内存泄漏风险(如
Handler匿名内部类持有Activity)。
- 第三方工具:
- LeakCanary:自动检测内存泄漏,生成泄漏路径(如单例持有
Activity引用)。 - BlockCanary:监控主线程阻塞,定位卡顿的具体方法和耗时。
- Matrix(微信开源):全方位性能监控(启动、内存、卡顿、IO 等),适合线上监控。
- LeakCanary:自动检测内存泄漏,生成泄漏路径(如单例持有
总结
Android 性能优化需围绕 “用户体验” 展开,核心是:
- 启动快:让用户快速进入 App 交互。
- 界面流畅:避免卡顿,动画自然。
- 稳定低耗:不闪退、不耗电、省流量。
优化过程中,需结合 工具量化问题(如用 Profiler 测启动耗时),再针对性优化,避免盲目优化。同时,性能优化是持续迭代的过程,需在开发、测试、线上监控全流程关注,平衡性能与功能开发效率。
其它
Systrace.py
/Users/xxx/Library/Android/sdk/platform-tools/systrace
第一种方案:
<style name="AppStartTheme" parent="AppTheme">
<item name="android:windowContentOverlay">@null</item>
<item name="windowBackground">@null</item>
<item name="windowDisablePreview">true</item>
</style>
第二种方案:
<style name="AppStartTheme" parent="AppTheme">
<item name="windowBackground">@drawable/bg_app_start</item>
<item name="android:windowFullscreen">true</item>
<item name="windowNoTitle">true</item>
</style>
查看字节码插件工具
ASM Bytecoder Viewer
Leakcanary 内存泄露 检查工具
handler.postDelayed(new Runnable(){
}, 1000);
会有内存泄露风险,因为匿名内部类可以持有外部成员的引用
在onDestroy(){}里调用 handler.removeCallbackAndMessages(null );
传个静态内部类,因为静态内部类不能持有外部成员的属性引用,通过传递软引用参数,
把外部成员设置进去
total Control
内存抖动:
profile
内存泄露
dump出来用mat查看,但是得用 sdk里 platform工具转化一下 成mat识别的格式
动态代理 retrofit 注解 + 反射 + 动态代理 封装okhttp
handler责任链模式
dispatchMessage(Message msg)
handleCallback(msg)
mCallback.handleMessage(msg)
handleMessage(msg)
图片压缩
LruCache 缓存
使用的LinkedHashMap
Bitmap内存优化
Bitmap自带的复用机制
复用,3.0之前不能复用,图片内存不用了,
但是如果在加载图片依然是分配新的内存,
这样容易浪费内存导致内存抖动
3.0-4.4 可以复用但是图片大小要一模一样 inSimpleSize为1
4.4之后 只要图片小于等于内存大小就可以
复用的是内存空间,防止内存抖动
3.0bitmap缓存在native
<8.0bitmap缓存到java
>=8.0又移回了 native
在java里面 jvm自动回收,如果在native
磁盘缓存
DiskLruCache
电量优化
数据结构优化
设计模式
启动优化
工具使用
systrace traceview
profile mat
Bitmap 优化
缓存
长图加载
Android存储优化
SharedPreference
commit 和 apply
支不支持多进程?
读可以,写不可以。
SQLite 也要有sql语句的优化
SQLiteStatement
使用事务
使用索引 原理
异步线程,写数据库统一管理
多线程写的时候,一般都先写到队列里,然后由队列写到数据库中
一般用第三方框架 GreenDao 、Realm
File 体积小 protobuf、7z压缩
ContentProvider
ContentResolver.call 可以实现进程通信
网络 -> 序列化/反序列化
protobuf
与平台无关
接口描述语言(Interface description language,缩写IDL)
https://developers.google.com/protocol-buffers/docs/overview
https://github.com/protocolbuffers/protobuf/releases
优势
- 简洁
- 体积小 值有xml的1/10~1/3
- 速度快 比xml快100倍
- protobuf编译系统,编译成java代码
- 兼容性好
项目中添加插件
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.10'
apply plugin:'com.google.protobuf'
implementation 'com.google.protobuf:protobuf-java:3.5.1'
Base-128变长编码
资料
Android性能优化
Android UI优化调试工具 Hierarchy Viewer 真机调试解决方法
Systrace工具使用
一张图一张图带你学习内存分析
Android App 启动优化全记录