从零优化一个android线上项目

337 阅读4分钟

公司的项目上线两年多,期间一直在上小米市场的时候出现内存溢出问题,导致上线失败,我们的做法就是:重新上传!!

现在空下来了就打算完完全全优化一遍。

首先,我们看下原来的内存图(设备:nexus6,系统:7.1.1)

Density is 3.5 densityDpi is 560 height: 2392 width: 1440


最高达到236M,最后稳定在170M左右。在最后一张引导页中,占用的内存是188.93M。内存占用这么大,这样不容易出现内存溢出才怪。

发现引导页和闪屏页面的大图,一律都放在了xhdpi文件夹中,这样在高分辨率的手机中,易导致内存溢出。

先来一条图片内存占用计算公式(density是该图片放在哪个文件夹就是哪个dpi,targetDensity是目标手机的dpi)


scaledWidth = int( Width * targetDensity / density + 0.5)

scaledHeight = int( Height * targetDensity / density + 0.5)

memory = scaledWidth * scaledHeight * 4

注意:png格式的ARGB8888是4个字节,而我们的图片是jpg格式,是3个字节。故这里只*3

随便一张引导图,大小是750*1334的,因为我们现在放的文件夹是xhdpi,所以

scaledWidth = 750*560/320 + 0.5 = 1313

scaledHeight = 1334*560/320 + 0.5 = 2335

memory = scaledWidth * scaledHeight * 3=1313*2335*3 = 9197565 = 8.77M

一张图占用了8.77M的内存。

如果将引导图放在xxxhdpi文件夹中,内存占用将是

scaledWidth = 750*560/560 + 0.5 = 750

scaledHeight = 1334*560/560 + 0.5 = 1334

memory = scaledWidth * scaledHeight * 3=750*1334*3 = 3001500 = 2.86M。

将4张引导图和1张闪屏图放到xxxhdpi后,观察内存图


可以看出来,第四章引导图显示的时候内存占用是122M,比优化前减少了66.8M。


接下来我们看内存泄露问题,点进去MEMORY之后,各个页面都进去点一点,争取覆盖多一些可能会因内存泄漏导致没有回收到的页面。然后点击Dump java heap。等一会儿,下面会出现dump图,我们选择排序方式为package,我们点到自己的项目包名里去,可以看到各个类的内存占用情况和个数


我们从头分析,主要关注一个类有多个实例的情况

WeakHandler.java

这个类有14个实例,点进去看右边有各自应用的地方

发现有个RegularPageAdapter是之前开发后来弃用的,于是删掉相关代码

发现很多类有多个实例,乍一看吓一跳,有这么多内存泄露吗?

点进去都看了下,原来大部分都是setOnClickListener的内部类持有外部类引用的原因,其实只要这里不执行耗时操作,就不会引起内存泄漏的。我们常说的handler容易引起内存泄露,也只是执行了延时操作才引起的。

一个个排查过去之后发现,应用中还是没有出现真正内存泄露的。

接下来分析页面加载速度的问题,因为发现有很多页面从点进去到用户能看到页面,耗时都比较严重,这是个大问题。

添加日志打印,BaseFragment和BaseActivity都加上。

我们看一个简单的页面的耗时情况:


正常情况,onCreate到onStart到onResume,保证在1-200毫秒之间,用户才不会感知到这个页面启动慢,我们再看看MainActivity的启动时间:


这里从onCreate到onStart就超过一秒了,这个启动时间令人捉急啊,我们赶紧定位onCreate代码,发现原来主要在于MainActivity初始化了4个Fragment,那没办法,主页面的4个Fragment都是必须要进入就加载的。暂时不优化。


我们再优化WebViewActivity


发现在WebViewActivity中,onCreate方法里做了一些不必要的,可以延时再做的初始化操作,如dialog的初始化,还要loadUrl这个可以放在handler里去做。

还发现setContentView首次进入竟然耗时少则1秒,多则2-5秒,怎么会这么耗时,点进去看布局文件,发现这里用了腾讯的x5内核webview。这真是严重影响用户体验啊,上网查下有没有别人被坑的。

一查果然发现,不少人问这个,还好最好发现解决方案,需要在application添加x5初始化的代码,QbSdk.initX5Environment(this,null);

再看日志,只花了60毫秒,完美解决x5内核setContentView耗时问题。

application发现onCreate方法花费了500毫秒,把不必要的初始化放在handler中进行初始化。这样application创建时间又减少了300毫秒。

我们再打开手机开发者选项里的显示过度绘制,发现手机一片红和绿,我们的目标是一片蓝,打开MainActivity的布局文件,发现有个背景色白色,然后看MainActivity中的各个Fragment,他们都设置了一遍背景色,去掉。