专项优化
列表页卡顿优化
常规方案
- ListView 复用View
- 在
getView
相关方法中有耗时操作,要采用异步处理
-
- 减少布局层级、避免过度绘制
- 采用异步 inflate 或者 X2C
图片相关
- 避免过大尺寸:GC 频繁、内存抖动
- 滑动时取消加载
合理使用线程池,避免主线程被过度抢占
TextView 优化
原因:面对复杂文本性能不佳,BoringLayout 单行、StaticLayout 多行、DynamicLayout 可编辑
展示类使用 StaticLayout 即可,性能优于 DynamicLayout
异步创建 StaticLayout
也可使用 TextLayoutBuilder 替换原 TextView
也还可以使用 google 在 Android 9.0 提供的
PrecomputedText
1
2
3Future<PrecomputedTextCompat> future = PrecomputedTextCompat.getTextFuture(
“text”, textView.getTextMetricsParamsCompat(), null);
textView.setTextFuture(future);
- 要留意字符串的拼接【备注:貌似编译器会自动转成
StringBuilder
进行append
】
存储优化
常规方案
- 确保 IO 操作发生在子线程
SharePreferences 相关
- 加载慢:初始化时会加载整个文件到内存中,虽然加载放在了异步线程,但是内部加锁,同样有 UI 线程等待异步线程的情况
- 全量写入:每次改动都会导致整体写入,无论改动的内容有多少
- 卡顿:Android 系统补偿策略导致,为了保证数据不会丢失,如在界面销毁时会进行一次全量保存,如果该操作执行时间较长,有可能出现卡顿、ANR 的情况
- 【一定要使用时】调优:尽可能的存储小文件,按业务区分模块存储来拆分文件,key可以考虑使用数值来替换长字符串来减少文件大小
- 【替换方案】MMKV:支持跨进程,通过mmap和文件锁保证数据完整性,支持增量写入、使用 Protocol Buffer,性能和安全性都优于SP
日志存储优化
要做到不影响性能、日志不丢失、安全
其它
- 常用数据缓存,避免多次读取
- 合理设置缓冲区Buffer大小:4-8KB
WebView 异常监控
WebView 版本众多以及对接的业务方众多,出现异常的概率比较大
资源释放
WebView 占用资源问题,在应用中只要使用一次WebView,资源就不能完全释放掉而占用内存。
解决方案:
为 WebView 开启一个独立的进程,使用
AIDL
通信,WebView 所在进程根据业务的需要在合适的时机进行销毁,达到正常释放内存的目的异常监控思路
监控屏幕是否白屏,白屏则有问题,所有像素都是同一颜色的则认为时白屏
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32/**
* 判断Bitmap是否都是一个颜色
* @param bitmap
* @return
*/
public static boolean isBlank(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
if (bitmap == null) {
return true;
}
int width = bitmap.getWidth();
int height = bitmap.getHeight();
if (width > 0 && height > 0) {
int originPix = bitmap.getPixel(0, 0);
int[] target = new int[width];
Arrays.fill(target, originPix);
int[] source = new int[width];
boolean isWhiteScreen = true;
for (int col = 0; col < height; col++) {
bitmap.getPixels(source, 0, width, 0, col, width, 1);
if (!Arrays.equals(target, source)) {
isWhiteScreen = false;
break;
}
}
return isWhiteScreen;
}
return false;
}