Android 性能优化总结

一、简介

性能调优是开发中少不了的一个过程,同时也是一名优秀的程序员需要掌握的基本技能。下面我们来看一下在 Android 中可以从哪些方面来进行性能优化吧。

二、内存优化

内存是很重要的一个模块了,所以我也将其放在了第一位来说明。那么如何来优化我们应用的内存呢?

当应用内存不足时,将发生内存溢出。内存溢出会直接导致应用 crash。尽量减少应用的内存使用将很好的避免发生内存溢出。我们可以从如下方面优化内存:

1. 内存泄漏

首先我们应该确保我们的应用不存在内存泄漏的情况。内存泄漏是指长生命周期对象持有短生命周期对象的引用,而导致短生命周期对象无法及时释放的问题,例如一个静态变量持有某个 Activity 的引用而导致该 Activity 退出时无法被回收。

Android 中常见的内存泄漏场景有:

  • Handler
    我们可以使用静态内部类的 Handler,并让 Handler 只持有外层 Activity 的弱引用;在 Activity 不再需要时,可以手动清空对应 Handler 中的所有消息。
  • 打开的资源未关闭
    例如文件、数据库等,打开后都是需要关闭的。这类问题通常比较好排查,使用一些代码检查工具(如 lint 等)都可以帮助你找到未关闭的资源。
  • 注册的回调没有注销
    一些回调方法,通常命名如 registerCallback 对应有 unregisterCallback,addCallback 对应有 removeCallback。这些回调都是需要我们成对使用的,否则很可能产生内存泄漏。
  • 单例模式持有的引用
    通常单例对象都是 static 的,其生命周期都很长。当单例对象持有某个短生命周期对象的引用时,如某个 Activity,将导致该 Activity 无法被系统回收。
    我们应该手动清除 Activity 的引用,或者是当单例中需要上下文时,直接使用 Application 作为其上下文。
  • 静态成员持有的引用
    该引用对象如果不再需要使用,应该手动将引用置为 null。
  • 非静态内部类的静态实例
    非静态内部类对象会持有外部类的引用,如果该非静态内部类对象是静态的,也将导致外部类对象无法被回收。

2. 图片

  • 图片压缩:对于大图片,可以压缩后加载(图片压缩方法可自行百度)。
  • 图片使用完后,及时释放。
  • 图片素材放在合适的目录下,如 xxhdpi、xxxhdpi 等,系统加载不同目录下的图片资源时,会根据手机 dpi 对其进行一定的缩放。一张较大的图片放在较低的 dpi 目录下容易导致系统加载时又进行放大而带来很大的内存消耗。
  • 图片缓存:当图片众多时,可以使用 来管理,并设置恰当的池大小(通常图片框架中都有相似实现了)。
  • 善用开源的图片框架吧。

3. 使用合适和数据结构

选用合适的数据结构,往往不仅可以减少内存的使用,也可以加快运算速度。你需要了解 队列数组链表哈希表 等常见数据结构,并根据实际场景选用合适的数据结构。

这里介绍两个 Android 推荐使用的,类似 键值对 功能的类:SparseArrayArrayMap。相比 HashMap,它们占用更少的内存,且功能相似,虽然性能上略逊一筹,但在 1000 以下的数量级上,性能上的差异基本可以忽略,但内存占用将少很多。

4. 其它优化

  • 使用 int 代替枚举
    枚举本质还是对象,比 int 多使用两倍左右的内存。不过枚举也有其优势,我们可以考虑使用 int 来代替枚举而减少内存。
  • 使用对象池
    对于需要频繁创建和释放的对象,我们可以考虑使用对象池来管理,通过重用对象来避免反复的创建释放。
  • ListView 的复用
    这个老生常谈了,通过 ViewHolder 重用布局。或者使用 RecyclerView

三、布局优化

1. 尽量选择使用简单的布局

简单的控件加载起来更快,当简单的控件可以满足需求时,应尽量考虑使用简单的控件。

常用布局控件复杂度:FrameLayout < LinearLayout < RelativeLayout

2. 减少布局的嵌套层级

当布局的嵌套层级增大时,将大大减慢 xml 的解析速度,而影响到页面的显示。所以我们应当保证布局的嵌套层级尽可能的低。

3. 其它优化

  • 使用 include 标签重用布局。
  • 合理的使用 merge 标签,可优化布局的嵌套层级。
  • 使用 style 标签,抽离公共的风格,可减少代码量,也更易维护。
  • 使用 ViewStub,对于某些不常用的控件,可在需要的时候再进行加载。

四、UI 卡顿优化

UI 卡顿将直接影响到用户的使用体验,是很重要的一个优化环节。

1. ANR

ANR 即页面无响应,产生原因有:Activity 中超过 5s 无响应;BroadcastReceiver 中,前台广播超过 10s,后台广播超过 60s;Service 20s 未完成启动;ContentProvider 的 publish 在 10s 没进行完等。

解决方法:避免在 UI 线程中进行耗时的操作,注意四大组件的大多数回调均在主线程中。

2. View 绘制慢

Android 的渲染需要在 16ms 内完成,否则会产生卡顿的现象。

避免在 onDraw() 方法中进行任何耗时操作,包括频繁创建局部对象(最好不要在该方法中创建局部对象)等。

避免频繁触发 view 的 layout 方法,因为会重新测量和绘制。

3. 动画

避免在同一时间执行过多的动画,导致 CPU/GPU 负载过大。

实现动画时,可以考虑一些开源的优秀的动画框架。

尽量使用硬件加速来完成动画。

4. GC(垃圾回收)

由于 GC 时将挂起其它所有线程,所以频繁的 GC 将带来卡顿的现象。

避免频繁创建释放对象,避免内存负荷大将减少 GC 的频率。

五、其它优化

1. 线程池

开启一个新的线程花销是很大的,如果应用需要经常创建新的线程,就考虑使用线程池吧。通过重用旧的线程对象减少创建新线程的开销。

2. 网络

一个页面的数据尽可能的放在同一个接口里,从而减少网络访问的次数。

大量的数据可以使用分页加载、缓存等。

3. IO

尽量减少 IO 的访问次数,例如读取一个文件时,一个字节一个字节的读取的话将频繁的访问 IO,我们可以一次性读取更多的字节而减少 IO 访问次数。

同理,数据库也是这样。

4. 代码量

尽量精简我们的代码,移除无用的资源和代码,选择使用更轻量级的依赖库。这也将大大减小我们 apk 的体积。

5. 运算

例如进行乘 2、除 2 等操作时,使用位运算(左移、右移)比乘除运算效率将好很多。尤其是这个运算发生在某个较大的循环体内时。

对于一些操作,我们可以选择使用 预处理延时计算 的策略。

6. 异常、锁

try - catch 和加锁的操作都是较重量级的,我们可以尽量不使用它们。例如一些线程同步的场景中选择使用 原子类volatile 关键字代替锁。

如果需要使用的场景下,我们也应该尽量保证其粒度足够小,即其包含的语句尽量少。

7. 更多

更多性能优化的方法,大家也可以留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值