欢迎页或者引导页设置不当导致OOM

开个头

开发中OOM (OutOfMemory Error)这个异常应该都遇到过。至于解决方法,就是告诉用户该换手机了(手动滑稽)

我遇到的OOM是在app第一次启动时,先进入欢迎页,然后进入引导页,然后OOM。确实是在部分手机才会遇到,主流的内存比较大的手机是没问题的。接下来就是解决这个OOM。

解决问题前先说明一下我的情况,欢迎页就是ImageView直接设置src一个本地图片,引导页就是一个ViewPager,子View是动态new ImageView,然后imageView.setImageResource()来加载图片。

当时偷懒只向UI要了一套 720x1280 的图片,然后放到了drawable文件夹下(是drawable,没有后缀)。然后导致加载图片的时候比正常加载图片(正常情况下,720x1280 应该放在drawable-xhdpi 或者 mipmap-xhdpi)消耗了更多的内存,导致小内存手机直接OOM。

找原因

为什么说我直接从drawable文件夹下加载图片,就会消耗更多的内存呢?我们先验证一下确实会消耗更多内存,然后再解释原因。
测试手机,小米4 1080x1920 480dpi density=3.0。测试图片像素都是 720x1280
我们怎样才能获取到图片加载时消耗的内存大小呢?众所周知android加载资源文件的图片时,是将图片文件转换为bitmap,然后再将bitmap设置到ImageView上,所以,我们拿到bitmap对象,看bitmap的大小就是 图片消耗的内存大小。

然后我写了个dome,SplashActivity,布局文件 根布局是LinearLayout,包裹一个ImageView。ImageView直接通过src设置加载的图片是在drawable文件夹下的test_1.png 。
通过 AndroidProfiler 来看下内存消耗
加载drawable文件下的图片
通过Profiler我们得知 直接加载drawable文件夹下的图片时,图片占用内存33177600 b (33177600/1024/1024 ≈31.64Mb),整个app占用内存69.5Mb,
然后我们复制一份图片到mipmap-xhdpi里面,然后重新运行,分析内存。
加载mipmap-xhdip文件夹下的图片
此时我们惊奇的发现,bitmap的大小变为8294400b(8294400/1024/1024 ≈7.91Mb),而真个app占用的内存也直接变为22.6Mb。

分析原因

为什么ImageView加载同一个图片文件时,文件存放的文件夹不一样,就会造成这么大的内存差异。
图片内存的计算方法参考了这篇博客。Android中一张图片占据的内存大小是如何计算

手机的dpi :phoneDpi,加载的图片的文件的dpi :targetDpi,图片分辨率 :width x height
图片转换为Bitmap之后的实际尺寸为 :(phoneDpi / targetDpi) * widht x (phoneDpi / targetDpi) *height
那么内存大小 = (phoneDpi / targetDpi) * widht x (phoneDpi / targetDpi) *height * 4 B
至于为什么是4B,因为Bitmap一般默认使用ARGB_8888 来存储像素点,也就是一个像素的大小是4B。

Bitmap.java

    public enum Config {
        //每个像素占 1字节
        ALPHA_8     (1),

    	//每个像素占2字节
        RGB_565     (3),

       	//每个像素占2字节
        ARGB_4444   (4),

        //每个像素占4字节
        ARGB_8888   (5),

       	//每个像素占8字节
        RGBA_F16    (6),
       ...
    }

drawable 文件夹对应的dpi 和drawable-mdpi一样,是 160dpi

DisplayMetrics.java
    /**
     * Standard quantized DPI for medium-density screens.
     */
    public static final int DENSITY_MEDIUM = 160;
   /**
     * The reference density used throughout the system.
     */
    public static final int DENSITY_DEFAULT = DENSITY_MEDIUM;

按照上面的方法我们来计算一下,在drawable文件夹下的720 x 1280的图片占用的内存。
Bitmap的宽 = 720 * (480 / 160) = 2160
Bitmap的高 = 1280 * (480 / 160) = 3840
Bitmap的大小 = 2160 * 3840 * 4 = 33177600 B ,和我们在 Android Profiler上看到的完全一致。

在mipmap-xhdpi (320dpi)文件夹下 720 x 1280 的图片占用的内存
Bitmap的宽 = 720 * (480 / 320) = 1080
Bitmap的高 = 1280 * (480 / 320) = 1920
Bitmap的大小 = 1080 * 1920 * 4 = 8294400 ,和我们在Android Profiler上看到的完全一致。

屏幕密度代表分辨率(px)屏幕像素密度(dpi)
低密度(ldpi)240x320120
中密度(mdpi)320x480160
高密度(hdpi)480x800240
超高密度(xhdpi)720x1280320
超超高密度(xxhdpi)1080x1920480

总结

  1. 图片加载到手机上占用的内存和 图片本身的大小无关,和图片的分辨率有关,和图片存放的资源文件的文件夹有关。
  2. 图片加载到手机上的实际宽(高) = (手机dpi / 图片对应dpi) * 宽(高)
  3. drawable或者mipmap对应的dpi 为 mdpi = 160
  4. 图片每个像素点默认占用4字节大小
  5. 图片加载到手机上的内存大小计算公式为,实际加载的宽(单位像素) * 实际加载的高(单位像素) * 每个像素占用的字节大小

然后最重要的一点是,不要偷懒,把正确的文件,放到正确的文件夹下。

如有错误,欢迎指正!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值