打算对性能优化写一个系列的文章,先以之前负责的项目为例,对性能方面的优化做个总结。
主要包括如下几个方面:
1、APK包的大小
APK包不能做的太大,太大了不太好推广,国内市场好像还好一些,国外市场就要受限了,因为在推广时会按包的体积大小收费,越精简,推广费用越低,越受欢迎;包越大,推广费用越高,推广者也不愿意接。
而对于普通的用户来说,肯定包越小,他下载的意愿会更强一些。
以下总结了一些压缩方向:
(1)、库
有多种方法,如果实现了同样的功能,可以用混淆的库代替源码库;库中的多国语言包,图片资源如果用不到可以删除;库中的某些模块用不到也可以将其删除。例如,google player service库,可以删除其中的无用部分。具体操作方法是通过解压缩工具,打开此库,然后将其中不用的模块删除即可。
具体哪些模块可以删除,可以参考,
http://stackoverflow.com/questions/21555662/android-app-size-increased-after-adding-admob-ads-using-google-play-services-lib
(2)、代码混淆
这个没有什么好说的,无论从代码安全性,还是压缩体积,删除无用代码,或者优化性能方面考虑,都需要进行混淆。混淆可以起到减少包大小的作用。
(3)、图片资源
删除无用的图片资源,可以借助Lint工具,查找无用的资源,然后依次删除。
还可以对图片进行压缩,可以使用工具,例如这个网站:https://tinypng.com/,提供在线压缩工具,直接将图片拖到压缩位置,然后点击压缩即可生成压缩文件,非常方便,一般能够将原始图片压缩60%-80%。
(4)、删除无用的代码,文字资源,xml等
Xml文件多了后会比较大,即使不使用,也会编译到apk包中,所以尽量删除无用的xml,代码和文字资源。
以上只是我在工作中实际操作的方法,而精简apk并不限于这些方法,还要根据项目的特性,具体情况还要具体分析,达到精简的目的。原理就是删除无用的,精简有用的,将包大小降到最低。
2、应用占用的内存
主要指Pss,它的意思是Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存),通过dumpsys meminfo 包名可以看到应用占用的内存大小,这个等同于在设置–应用中看到的service或者缓存大小。
例如,(表示项目包名,这里我将实际包名替换成了xxx.xxx.xxx)
shell@android:/ # dumpsys meminfo xxx.xxx.xxx
dumpsys meminfo xxx.xxx.xxx
Applications Memory Usage (kB):
Uptime: 71794048 Realtime: 122022986
** MEMINFO in pid 588 [xxx.xxx.xxx] **
Shared Private Heap Heap Heap
Pss Dirty Dirty Size Alloc Free
------ ------ ------ ------ ------ ------
Native 0 0 0 4364 3153 6
Dalvik 19772 5680 19688 19260 18951 309
Cursor 0 0 0
Ashmem 0 0 0
Other dev 20404 40840 0
.so mmap 1502 2576 1228
.jar mmap 0 0 0
.apk mmap 112 0 0
.ttf mmap 435 0 0
.dex mmap 1736 0 8
Other mmap 815 328 176
Unknown 1778 296 1776
TOTAL 46554 49720 22876 23624 22104 315
可以看到Pss总大小为46554kB。
具体哪些模块占用多少内存,哪些有内存泄漏的隐患可以通过MAT工具进行优化,查找内存使用大的模块,一般有图片相关的功能时,bitmap占用是大头。
例如,
以下是应用中切换自定义主题后测试版本占用内存的分析。
从MAT分析的结果看有四处:
(1)、xxx.xxx.xxx.ui.WindowView占用2,903,680 (15.52%) bytes。
(2)、xxx.xxx.xxx.ui.ViewPager使用的bitmap占用内存为2,764,648 (14.78%) bytes.
(3)、xxx.xxx.xxx.ui. FloatImageButton使用的bitmap占用内存为2,536,984 (13.56%) bytes.
(4)、” xxx.xxx.xxx.ThemeLogic使用的bitmap占用内存为1,963,280 (10.49%) bytes.
可以看到前3块内存是系统预置的图片占用的内存,第4块是管理自定义主题后占用的内存,他们的使用的都是和bitmap相关的,可以统一管理起来。
优化方向:
(1)、
Android有一个机制,应用退出后会有一个缓存一直存在,这样便于以后启动。但这个后台缓存作用其实并不大,并且第三方内存统计软件会将其统计到内存使用中,所以可以在应用退出时考虑将后台缓存清除。
方案是客户端程序退出10秒后,将后台缓存杀死。杀死后台缓存不会影响到后台进程,这样能降低到原来内存占用的一半或者不到一半的样子(对于双进程或者多进程的应用比较有效,因为界面进程退出后,它的服务进程并没有退出,所以可以考虑将界面进程即缓存杀掉)。
(2)、
去掉硬件加速配置android:hardwareAccelerated=”true”,可以节省内存。
硬件加速会占用一些内存,具体表现在使用 dumpsys meminfo统计到的Other dev字段中,去掉其后,内存占用经测试会小一些。但后果可能会影响画图的效率,但是否真正造成实际使用的影响,需要测试多验证,但从一些其它应用比如单手划划反编来看,都没有此设置,所以感觉可以去掉。
(3)、
修改图片缓存机制,将private ArrayList
(4)、
将预置的图片资源也要加到缓存中,切换自定义主题后可以删除。
因为预置的图片都是以类似.xml方式提供的,如下所示,
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ ic_root " android:state_pressed="false"/>
<item android:drawable="@drawable/ ic_root_pressed " android:state_pressed="true"/>
</selector>
要对其中的bitmap进行分开解析,然后存储。
将预置图片也保存到缓存中,和自定义主题统一管理。程序主要占用内存的地方是bitmap,只要将这部分内存降下来,并且合理管理起来,例如切换主题时不产生内存泄露,及时释放,就能将程序内存降下来。优化的方向是通过解析预置图片,将其保存到了 lrucache 结构中进行管理,也起到的很好的作用。通过MAT内存工具可以看到,在将预置主题切换到自定义主题时,之前出现的预置图片多占用的内存已经不存在了。
(5)、
确保系统中用到的资源都能放到缓存中,重点是自定义主题部分;方法同4介绍的相同。
以上就是针对内存优化的解决方案,优化方向主要是DALVIK层,对bitmap使用的优化。优化后在悬浮窗待机情况下,可以维持在一个较小的范围之内(从测试结果看有的手机保持在20M-30M左右)。
如果有时间和精力可以再研究一下Other dev,.so map,unknown占用的内存优化方法。
3、启动的service尽量少。如果启动多个可以将其放到一个进程中
这样用户在设置中看到的进程和服务会少一些。
4、耗电优化
这个主要是查找一下待机情况下是否有应用在工作,比如timer有没有停掉?程序退出了后台服务还在工作,和服务器端交互,是否在收发数据?有没有长连接等。
这个需要对项目代码有个充分的了解,再有一些预判的情况下,才能很好的定位问题。
还有一种方法,可以在debug模式下,通过打log来发现一些蛛丝马迹。
以上是根据之前负责的项目优化情况做的一个总结,大家可以参考学习,有问题也可以随时讨论。