关于android中bitmap使用时的oom的一些解决方法

本文探讨了Android中由于Bitmap导致的OOM问题,指出Android系统分配给Bitmap的内存有限,过多加载大图将引发异常。文章介绍了四种解决方法:1) 图片压缩,2) 及时回收Bitmap内存,3) 异常捕获防止应用崩溃,4) 缓存复用Bitmap对象。通过这些方法可以有效管理Bitmap内存,防止内存泄漏。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景:

这些天弄一个关于relativelayout中设置高斯模糊图片的事情,需求是从网络上获取到该背景图片.图片过大

做完后感觉还行,但是测试的时候发现背景多加载几次就会oom,通过as上的memory可以看到每次加载内存都会增加,但是却不会减少,通过查了一些资料发现以下一些结论:

在Android应用里,最耗费内存的就是图片资源。而且在Android系统中,读取位图Bitmap时,分给虚拟机中的图片的堆栈大小只有8M,如果超出了,就会出现OutOfMemory异常,但是在开发android的时候,很少会注意或者意识到释放内存的重要性,因为大家在使用过程中,涉及的图片资源不多,或者比较稳定,来回切换界面,图片也就那么几张或者使用的都是很小的图片,根本不会感觉到图片占用内存可能引发的潜在危机.

解决方法:

1,压缩图片

bitmap过大会产生oom,首先,这种方式是通过牺牲图片效果的方式的,所以压缩后可能效果没之前好了,但是我的需求本来就是需要高斯模糊,说白了就是模糊一点,所以图片效果并不是很重要,所以,压缩是可行的….方法是通过网络获取图片的流,代码如下

`new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    BitmapFactory.Options options = new BitmapFactory.Options();
                    //这里设置为true则不会在内存创建空间,即这个bitmap = null,这样就相当于获取了流中的数据却没有浪费内存
                    options.inJustDecodeBounds = true;
                    BitmapFactory.decodeStream(new URL(background).openStream(), null, options);
                    //通过这两个方法可以得到图的宽高  这里重点是options,,这个是bitmap的压缩标准
                    int width = options.outWidth, height = options.outHeight;
                    int scale = 1;
                    int temp = width > height ? width : height;
                    //通过循环得到合适的压缩值 , scale的值得到后 ,  压缩为之前的 1/scale
                    while (true) {
                        if (temp / 2 < 120)
                            break;
                        temp = temp / 2;
                        scale *= 2;
                    }
                    //我这里重新创建了一个opt,也可以不创建
                    BitmapFactory.Options opt = new BitmapFactory.Options();
                    //这里的inJustDecodeBounds不能为true,默认就是false,加入上面不创建的话这里需要options.inJustDecodeBounds = false 的声明,否则bitmap=null,
                    opt.inSampleSize = scale;
                    //这里的bitmap不为空了,并且已经是压缩之后的bitmap了 , 通过代码可以知道,宽高都不会大于240;
                    Bitmap bitmap = BitmapFactory.decodeStream(new URL(background).openStream(), null, opt);
                    blur(bitmap);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();`

2,及时回收bitmap的内存,来释放空间(1最重要 2没有1重要,但也非常必要)

Bitmap类有一个方法recycle(),从方法名可以看出意思是回收。这里就有疑问了,Android系统有自己的垃圾回收机制,可以不定期的回收掉不使用的内存空间,当然也包括Bitmap的空间。那为什么还需要这个方法呢?Bitmap类的构造方法都是私有的,所以开发者不能直接new出一个Bitmap对象,只能通过BitmapFactory类的各种静态方法来实例化一个Bitmap。仔细查看BitmapFactory的源代码可以看到,生成Bitmap对象最终都是通过JNI调用方式实现的。所以,加载Bitmap到内存里以后,是包含两部分内存区域的。简单的说,一部分是Java部分的,一部分是C部分的。这个Bitmap对象是由Java部分分配的,不用的时候系统就会自动回收了,但是那个对应的C可用的内存区域,虚拟机是不能直接回收的,这个只能调用底层的功能释放。所以需要调用recycle()方法来释放C部分的内存。从Bitmap类的源代码也可以看到,recycle()方法里也的确是调用了JNI方法了的。不管怎么说,释放空间还是用代码的,代码如下

    `
    //这里的意思是无论你是在xml中布局使用了android:background,还是在java代码中调用了setBackground( background );
    //setBackgroundDrawable( background);setBackgroundResource(resid)等的方式去设置了背景图片.
    //请在不需要的时候调用一下对应的方法
    //setBackgroundResource和 android:background → setBackgroundResource(0);
    //setBackgroundDrawable( background) → setBackgroundDrawable (null)
    //setBackground ( background ) → setBackground (null)  
    //也就是说释放不了对象很多原因就是缺少这句代码的
    mUserDetailBackground.setBackground(null);
    //这是释放代码的方法
    if (backgroundBitmap != null && !backgroundBitmap.isRecycled()) {
        backgroundBitmap.recycle();
        backgroundBitmap = null;
    }
    if (bitmapDrawable != null && !bitmapDrawable.getBitmap().isRecycled()) {
        bitmapDrawable.getBitmap().recycle();
        bitmapDrawable = null;
    }
    //最后在onDestoy中调用gc方法
    @Override
    protected void onDestroy() {
        super.onDestroy();
        System.gc();
    }`

3,对程序要进行异常捕获

通过因为Bitmap是吃内存大户,为了避免应用在分配Bitmap内存的时候出现OutOfMemory异常以后Crash掉,需要特别注意实例化Bitmap部分的代码。通常,在实例化Bitmap的代码中,一定要对OutOfMemory异常进行捕获,所以我这里全部对异常进行了捕获,就是为了避免万一出问题而导致Crash,这段没代码,就是把代码try catch起来

4,缓存通用的Bitmap对象

这一段我没用到,但是网上看到的,感觉挺不错,就分享出来了.

有时候,可能需要在一个Activity里多次用到同一张图片。比如一个Activity会展示一些用户的头像列表,而如果用户没有设置头像的话,则会显示一个默认头像,而这个头像是位于应用程序本身的资源文件中的。如果有类似上面的场景,就可以对同一Bitmap进行缓存。如果不进行缓存,尽管看到的是同一张图片文件,但是使用BitmapFactory类的方法来实例化出来的Bitmap,是不同的Bitmap对象。缓存可以避免新建多个Bitmap对象,避免内存的浪费。

以上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值