性能优化是移动端开发绕不过的一个问题,毕竟硬件资源有限,而且业务也越来越复杂,不优化的话体验很差,严重的话整个程序都可能无法运行。
网上已经有了很多关于性能优化的优秀文章,这里我也来小结下,算是对自己以前做的事情的总结吧。
首先,性能包含哪几个方便?然后,针对每一个方面,我们应该从什么入手来优化,如何去量化性能优化?
我们要先想清楚这几个问题,因为这样我们做性能优化才有一个清晰的目标,才知道需要朝哪几个方向去努力,通过可以量化的数值,我们才好判断说我们的优化取得的成果。
个人认为性能优化包含以下方面,没有列举完全,后续会补充。
我们一个一个的来说。
这是一个比较容易量化的点,直接看编译后生成的 apk 的文件大小就好了。
我们可以尝试把一个 apk 文件拖拽到 as 里面,你会看到如下图所示的内容。
可以看到占用资源比较多的是
我们可以从这三个方面来减少 apk 的体积
一般 res 里面的文件比较多的是图片,像一些预置的图片啊啥的。因为要做到一些效果,所以这些图片不能轻易删除,虽然不能删除,但是我们可以用下面的方法来减少图片的文件大小从而减小 apk 的体积。
还有一种比较常见的方法是利用 as 的 lint 工具来扫描哪些资源是没有被使用的,没有被使用的资源可以删除,已减小 apk 的体积。一般由于业务和需求的变更和积累,多少都有些没有使用到的资源,用这个方法可以减小一部分的体积
还有一种方法就是利用微信开源的一款工具 AndResGuard。这个工具是一个资源混淆工具,原理是资源名称如果比较长的话,在编译到 apk 的过程中,这些文件名也是需要被记录的,通过资源名称混淆,我们可以减小文件名称的记录,从而达到减小文件大小的目的,同时也保护了我们的资源。
so 库的话,没有特别的优化方法,但是有一些小技巧还是可以做的,如果你开发的 apk 只运行在 arm 平台上,你可以在编译脚本里面这样写
...
defaultConfig {
...
ndk {
abiFilters "armeabi"
}
}
...
abiFilters
这个配置项会在打包 apk 的时候只编译指定平台的 so , 在上面的例子就是只打包 armeabi 下的 so 库。可配置项大概有下面几种
大家可以根据需要配置。配置后 apk 的体积一般会小一点
dex 文件里面就是我们写的代码和一些第三方库的代码了,减少 dex 文件的大小就是减少代码了,我们可以通过下面几个方法来减少代码
对于第一条,没什么好说的,多个相同或者类似功能的库,不仅会导致生成的 dex 变大,同时在运行的时候是也会浪费一些资源,同时方法量也会上去,会导致 apk 方法数超过 65536 ,这是很得不偿失的做法。
对于第二条,混淆。混淆有许多好处,可以较大程度保护自己的代码,因为混淆后,一些类名、方法和属性都被修改为无意义的字母,别人反编译的时候也不容易看懂逻辑,同时代码混淆后的编译生成的字节码也会少一些。这样也达到了减小体积的目的。
启动速度应该是一个很重要的指标了,因为是用于使用 app 的第一印象,如果启动过慢,会给用户很不好的体验和印象,所以 apk 的启动速度优化还是很有必要的。app 的启动速度优化,网上有很多优秀的文章,《Android性能优化(一)之启动加速35%》、《一触即发——App启动优化最佳实践》 等,大家可以参考下。
这里我总结一下我平时工作中用到的方法吧。
有几种方法来测量一个应用的启动耗时,我们先来分析下冷启动(即启动之前没有 app 的进程)的过程
- Application 构造方法
- attachBaseContext()
- onCreate()
- 入口Activity的对象构造
- setTheme() 设置主题等信息
- 入口Activity的onCreate()
- 入口Activity的onStart()
- 入口Activity的onResume()
- 入口Activity的onAttachToWindow()
- 入口Activity的onWindowFocusChanged()
以上就是 app 冷启动过程。我们在第一个方法开始获取一个开始时间戳,然后最后一个方法结束获取一个结束时间戳,这两个时间戳的差就是这个应用的启动时间了。
还有一种方法来获取 app 的启动时间,那就是通过 adb ,你可以用下面的命令来启动一个应用,终端会打印出来启动时间的信息。
adb shell am start -W [PackageName]/[PackageName.MainActivity]
终端输入这个命令后,一般会打印类似下面的信息
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=PackageName/.MainActivity }
Status: ok
Activity: PackageName/.MainActivity
ThisTime: 1818
TotalTime: 1818
WaitTime: 1829
Complete
ThisTime 、 TotalTime 和 WaitTime 表示的时间如下所示
通过这个方法我们也可以拿到 app 的启动时间。
我们拿到 app 的启动时间后,只是知道了结果,我们需要分析过程,找出耗时的过程才好优化启动速度,所以我们如何获取详细的启动过程呢?
在优化过程中主要遇到以下的问题
时间原因,后续补充