Android性能优化--卡顿优化与布局优化

一般而言,CPU 除了需要计算 View 对应的图形和向量等信息,还要做逻辑运算和文件读写等任务,所以 CPU 造成卡顿更常见。一般也是通过减少 CPU 的计算任务来优化卡顿。

影响 CPU 的使用率一般有以下几个方面:

  • 读写文件。

  • 解析大量图片。

  • 频繁请求网络。

  • 复杂的布局。

  • 频繁创建对象。

如何检测卡顿

深入探索Android卡顿优化

深入实战Android卡顿优化

GitHub - xanderwang/performance

详细的原理,可以参考上面的连接,这里简单总结下监控 UI 卡段的原理。

我们知道,Android 里面,界面的刷新需要在主线程或者说 UI 线程执行。而界面的绘制起始点又利用了 Looper 消息循环机制。Looper 消息循环机制有一个有意思的特点,就是 Looper 在 dispatch Message 的时候,会在 dispatch 前和 dispatch 后利用 Printer 打印特定 tag 的字符串,通过接管 Printer ,我们就可以获取 dispatch message 前后的时机。

然后我们可以在 dispatch message 之前,在异步线程启动一个抓取系统信息的延时任务。在 dispatch message 之后,我们可以移除异步线程的这个延时任务。如果某个消息的执行没有超过阈值,那就表示在异步线程的延时任务被取消,表明没有卡顿。如果某个消息的执行时间超过了阈值,那异步线程里的延时任务就会执行,表明有卡顿,异步线程的延时任务会获取此时的系统状态,从而辅助我们分析卡顿问题。

如何优化卡顿

如何检测说完了,我们来说说如何优化。在 为什么会卡顿 小结我总结了几种常见,现在对几种场景的优化总结下。

读写文件

最常见的一个读写文件而不自知的就是 SharePerfrences 的使用,使用 sp 的时候需要注意不要频繁调用 apply 或者 commit 方法,因为每调用一次就有可能会有一次写文件操作(高版本系统做了优化 apply 做了优化,不一定会写文件)。所以,如果调用次数多的话,就会多次写文件,写文件又是一个耗时且耗资源的操作,所以要少做。

一般优化方法是合理拆分 sp 文件,一个 sp 文件不要包含太多的项,同时每一项的内容尽量短。尽量批量提交数据后再 commit 或者 apply 。同时需要注意的是 commit 会直接触发写文件(内容有变化的时候),所以如果在 UI 线程调用 commit 方法需要注意可能会阻塞 UI 线程。

如果有更高的性能需求,可以考虑用 mmkv 来替换或者 DataStore 来替换 sp 。具体的替换方法就不细说了。网上有很多资料参考。

https://github.com/Tencent/MMKV

https://developer.android.google.cn/topic/libraries/architecture/datastore?hl=zh-cn

另外一个常见的读写文件的场景是从 xml 文件里面读取布局、色值等操作,这些都是一些 io 操作。从 xml 读取布局的话,可以考虑用代码直接创建 view 来优化,从 xml 里面读取颜色可以考虑加个 HashMap 来优化。

解析大量图片

解码图片毫无疑问是一个计算量大的操作,所以一般加载图片的时候最好根据实际显示的尺寸做压缩,并且保存压缩后的缩略图,方便下次直接加载。

另外还需要注意列表滚动过程中,控制对图片的加载,一般列表在滑动过程中,不加载图片,等列表滚动停止后,才开始加载图片。

另外的一个优化的方法就是减少图片的使用,不过这个难度有点大。

另外还可以考虑针对不同的图片格式,用不同的解码格式。比如 png 格式的图片根据机器实际情况选择 8888 或者 4444 解码方式解码图片。如果是 jpg/jpeg 格式的图片,就用 565 的解码方式解码图片。对于用不同的解码方式解码图片,效率是否会高,本人没做过测试,但是毫无疑问,内存的使用是不同的。

频繁请求网络

网络请求的话,可以参考下面的优化方法。

1、如果使用 okhttp 请求网络的话,尽量全局使用一个 httpclient ,这样做的好处是可以复用,提高网络请求效率。

2、后台支持的话,开启 gzip 压缩,这样网络传输的数据量小些,传输效率会高些。

3、自定义 dns ,减少解析 dns 的时间。

4、通过和后台商量,部分数据后台接口一步到位,尽量避免多次请求后才拿到完整的目标数据。

复杂的布局

  1. ​​减少不必要的背景色,去掉子控件中和父控件一样的背景色;去掉父控件中被子控件完全覆盖的背景色
  2. 减少布局层级:使用约束布局ConstraintLayout;使用include和merge增加复用,减少层级
  3. 使用ViewStub按需加载,更加轻便
  4. 能用LinearLayout和FrameLayout,就不要用RelativeLayout,因为RelativeLayout控件相对比较复杂,测绘也想要耗时。

Android 布局优化真的难,从入门到放弃

深入探索Android布局优化(上)

布局优化详细

频繁创建对象

为什么这个要列出来呢?因为频繁创建对象,可能会短时间内消耗大量内存,然后内存不足的时候系统就会尝试 GC 来回收对象,而 GC 是很耗资源的操作,虽然现在 Android 系统对 GC 做了很多优化,但是尽量减少 GC 的触发总是好的。

一般频繁创建对象的场景有:

  • 自定义 View 的时候,在 onDraw 方法创建临时对象。

    循环里面使用 "+" 拼接字符串。

  • ArrayList 等有容积限制的容器类初始化的容量不合理,导致后续新增数据频繁扩容。

除了频繁创建对象可能会触发 GC ,如果某次使用过大的内存也可能会导致 GC ,比如展示一个超大的 Bitmap ,虽然可以用缩略图来展示,但是可能会碰到需要放大查看具体细节的场景,这个时候可以考虑采用裁剪显示区域(BitmapRegionDecoder)的方式来解析图片。

绘制优化:

  1. onDraw中不要创建新的局部对象
  2. onDraw方法中不要做耗时的任务

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值