美文网首页AndroidAndroid性能优化与实践
「全面理解Android内存优化 3」-从理论到实践

「全面理解Android内存优化 3」-从理论到实践

作者: 林栩link | 来源:发表于2019-08-18 12:42 被阅读0次

    前言

    本篇文章是《全面理解Android内存优化》系列文章的最后一篇。系列的主要目的是希望将Android开发中涉及性能优化的部分做一次系统的归纳、总结和学习。本系列文章包含理论基础工具使用项目实践三个部分。

    理论基础:「全面理解Android内存优化 1」-Android的内存机制与管理建议,主要讲解Android性能优化时涉及到的各种基础知识

    工具使用:「全面理解Android内存优化 2」-内存优化工具的使用,主要讲解Android性能优化时各种常用工具的使用。

    项目实践:「全面理解Android内存优化 3」-从理论到实践,以一个实际APP为例,总结在在开发中会被忽视的内存问题。

    本文中实战时使用的项目地址:https://github.com/linux-link/Fan,可以先阅读这篇文章了解这个项目一次组件化与Android Jetpack的实践

    本篇属于三个部分中的项目实践部分。

    目录

    • 关闭无用的Service
    • 多进程WebView的优化
    • 避免一图毁十优
    • 总结

    正文

    一、关闭无用的Service

    《饭fan》是一个单Activity多Fragment的APP,在App的入口Activity同时启动了两个Service,TinkerService用于检查热修复补丁,UpdateService用于检查是否有更新。

    在操作APP一段时间后,使用Memory Profiler检查内存,得到下图

    image

    可以看到内存中依然存在TinkerService和UpdateService。没有特殊指定的service是运行在主线程中的,这些已经无用的Service会拖慢主线程并占据主进程的可用内存。

    解决方案

    • 调用stopService或stopSelf关闭这些service

    关闭service后再次使用Memory Profiler检查内存,可以看到,APP占用的总内存已经减少了

    image

    二、多进程WebView的优化

    从1.0.3版开始《饭fan》中集成了一个简单的商城系统,商城系统的制作参考了
    慕课网的一个课程—《混合开发入门 主流开发方案实战京东移动端APP》

    商城系统集成完毕后,调试过程中,LeakCanary提示,ShoppingActivity发生了内存泄漏,如下图所示

    image

    WebView应该是Android中最容易发生内存泄漏的系统组件,往往都是Activity退出时,WebView依然持有activity的引用,导致Activity发生泄漏。 网络上有很多如何防止WebView产生泄漏,但是效果都不好,有的甚至根本没有效果。

    解决方案

    • 让持有webview的Activity独立运行在一个进程,在activity的onDestroy中关闭这个进程

    让Activity独立运行在一个进程中,可以彻底清除掉webview以及Activity
    ,但是让持有webview的Activity独立在一个进程中,会产生另一个问题——长时间的白屏。
    webview本身初始化以及载入Html页面都需要一定的时间,这段时间会产白屏。
    如果在启动Activity时需要额外再创建一个进程,那么白屏的时间就会进一步拉长,有时甚至长达4-5秒。

    《饭fan》中针对长时间这个问题,又做了进一步优化。

    • 1.在app启动时,同时启动一个ShoppingService。ShoppingService运行在与WebViewActivity相同的进程中,退出WebViewActivity后当前进程会被关闭,在适当时候再重启ShoppingService。
    • 2.引入腾讯的x5WebView和VasSonic,加快webview初始化速度,同时也提高了WebView在各个系统上兼容性。
    • 3.在webview初始化的同时,使用APP内网络框架来请求Html页面中所需的数据。通过并行的方式,节省webview的加载数据的时间。

    优化步骤大致就是以上这些,具体实现的代码请参考《饭fan》中Component_shopping组件。

    三、Bitmap造成的内存泄漏

    在Android内存优化中有“一图毁十优”的说法,一般普通的内存泄漏浪费的内存都在几十KB到几MB之间,但是一个bitmap泄漏就有可能浪费几十MB的内存空间,所以bitmap的优化一直是Android内存优化的重中之重。所以我们接下来的就重点介绍Bitmap的优化方案。

    • 1.使用RGB_565解码图片

    在开发中大多数的图片加载框架的默认解码方案是ARGB_8888,这种解码方案,每个像素占4个字节,其实还有一种图片解码方案是RGB_565,这种解码方案,每个像素占2个字节,但是在视觉效果上与ARGB_8888差距并不明显。

    所以一些页面的缩略图、背景图片以及一些用户感官上认为它就是缩略图的地方可以使用RGB_565来解码,在减小内存占用上,有立竿见影的效果,强烈推荐使用。

    • 2.不要乱放图片

    在开发中我们往往会要求美工一张图标切3到5套不同尺寸的,然后分别放置在res下不同的资源目录里面

    目录 对应的dpi
    res/drawable 0
    res/mipmap-lidp 120
    res/mipmap-mdpi 160
    res/mipmap-hdpi 240
    res/mipmap-xhdpi 320
    res/mipmap-xxhdpi 480
    res/mipmap-xxxhdpi 640

    Android有一套特殊的适配策略,对放在mipmap目录的图标会忽略屏幕密度,会去尽量匹配大一点的,然后系统自动对图片进行缩放,从而优化显示和节省资源。图片的缩放比率=手机的dpi / mipmap目录的dpi。

    放在drawable目录下的会根据ROM的不同得到一个默认的dpi,但是这个dpi并一定是手机屏幕的实际dpi。

    例如:如果我们将一张500X500的图标仅放在ldpi(120)下,那么在在480dpi的手机上实际的显示尺寸是2000X2000。

    当我们分不清图标应该放在哪个目录下时,应该尽量将高品质的图片放在高密度目录下,这样能控制图片的缩放比率小于1,保证画质的前提,内存也是可控的。

    • 3.控制那些不可控的图片

    这是什么意思呢,举一个我曾经实际遇到的例子,我们的APP有一个课件的功能,允许教师上传课件,服务器会把这些课件转成图片返回给APP显示,有个老师上传了一篇PDF格式的论文,服务器转换后每个图片足足有4000X8000这么大,加载每张图片需要消耗内存4000X8000X4/1024/1204=122MB,直接导致了OOM。

    在这个例子中教师上传的课件转换后的图片就属于不可控图片,如果服务器不做过滤,那么APP就需要对这些用户上传的图片特殊处理。

    处理步骤如下:

    • 从服务器下载的图片获取它的高度和宽度
    • 对于高度或宽度大于手机屏幕尺寸的图片计算缩放比率,并做缩放解码
    • 要对所有的图片解码API(decodexxxx)做OutOfMemoryError的异常处理

    具体的代码请参考BitmapUtils

    四、总结

    本篇主要总结了一些开发中常常被忽视的内存问题,其它常见的内存问题,在第一篇文章已经有所提及,不过正是这些被忽视的问题切切实实地占据了手机中大量的内存,这些问题其实才是我们更应该关注的重点。

    参考资料

    《Android移动性能实战》-腾讯SNG专项测试团队 编著

    相关文章

      网友评论

        本文标题:「全面理解Android内存优化 3」-从理论到实践

        本文链接:https://www.haomeiwen.com/subject/utsrsctx.html