Bitmap的OOM问题解决

简介

内存溢出主要是由于图片过大导致加载图片的内存过大而出现的Exception。而解决方法就是通过BitmapFactory加载图片时使用BitmapFactory.Options对相关参数进行配置来减少加载的像素。

方法

我们获取的主要方式有以下三种:


  • 网络获取
  • 文件
  • 资源文件

  • 解决方法:
    • decodeStream()
      • decodeStream最大的秘密在于其直接调JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。
      • 因此,建议使用BitmapFactory.decodeStream来代替createBitmap方法。
  • 使用压缩读取
    • 首先,要分两种情况,如果是从网络获取到的要先把网络资源下载到本地,就是先缓存下来,之后,-.-,重新从内存读取,使用BitmapFactory.Options和BitmapFactory.decodeFile进行压缩读取。
  • 要养成良好习惯用完Bitmap要及时释放内存
    • 使用Bitmap的recycle()方法进行释放内存。-.-|||,有点不明白就是这小家伙不是及时释放的,但是我在设置了之后,会在重启该Activity的时候释放之前的Bitmap所占用的内存。

代码


1.压缩读取

public class Article {

    private String id;
    private String imagelink;

    public void setId(String id) {
        this.id = id;
    }

    public void setImagelink(String imagelink) {
        this.imagelink = imagelink;
    }

    public String getId() {
        return id;
    }

    public String getImagelink() {
        return imagelink;
    }

}

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * Created by Notzuonotdied on 2016/8/15.
 */
public class getImage {

    /**
     * Gets bitmap.
     *
     * @param mArticle        文章对象
     * @param reWidth         要求的宽度
     * @param reHeight        要求的高度
     * @return the bitmap 返回图片Bitmap
     */
    public static Bitmap getBitmap(Article mArticle, int reWidth, int reHeight) {
        return getBitmapFromEX(downloadIntoFile(mArticle),
                reWidth, reHeight);
    }

    /**
     * 获取图片
     *
     * @param fileName 图片缓存的地址
     * @param reWidth  要求的宽度
     * @param reHeight 要求的高度
     */
    private static Bitmap getBitmapFromEX(String fileName, int reWidth,
                                          int reHeight) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(fileName, options);
        // 设置缩放比例,对大图片进行压缩
        options.inSampleSize = getTheBestinSampleSize(options, reWidth, reHeight);
        options.inJustDecodeBounds = false;
        // inPreferredConfig 的默认值是ARGB_8888,改为RGB_565,可以省内存,降低消耗。
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        return BitmapFactory.decodeFile(fileName, options);
    }

    /**
     * 获取最佳的缩放值
     *
     * @param options  BitmapFactory.Options
     * @param reWidth  要求的宽度
     * @param reHeight 要求的高度
     */
    private static int getTheBestinSampleSize(BitmapFactory.Options options,
                                              int reWidth, int reHeight) {
        // Math.round四舍五入取整
        return options.outWidth > reWidth || options.outHeight > reHeight ?
                Math.min(Math.round((float) options.outWidth / (float) reWidth),
                        Math.round((float) options.outHeight / (float) reHeight))
                : 1;
    }

    /**
     * 下载图片,并且将图片保存到内存卡中
     *
     * @param article 导入一个对象
     */
    private static String downloadIntoFile(Article article) {
        String photoPath = Environment.getExternalStorageDirectory()
            .getPath() + "/Test/images/";
        String imageLink = getConnect.myUrl + article.getImagelink();
        Environment.getExternalStoragePublicDirectory(photoPath);
        File fileDirectory = new File(photoPath);
        if (!fileDirectory.exists()) {
            if (fileDirectory.mkdirs()) {
                Log.i("Notzuonotdied", "创建文件夹成功!");
            }
        }
        File tempFile = new File(photoPath, article.getId());
        if (tempFile.exists()) {
            return photoPath + article.getId();
        }
        try {
            if (tempFile.createNewFile()) {
                Log.i("Notzuonotdied", "新建成功!");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 流
        InputStream is = null;
        FileOutputStream fileOutputStream = null;

        try {
            URL url = new URL(imageLink);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestProperty("Content-type", "application/x-java-serialized-object");
            conn.setDoInput(true);
            conn.connect();
            is = conn.getInputStream();

            fileOutputStream = new FileOutputStream(tempFile);
            byte[] bytes = new byte[1024];
            int len;
            while ((len = is.read(bytes)) != -1) {
                fileOutputStream.write(bytes, 0, len);
            }
            fileOutputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return photoPath + article.getId();
    }
}

代码解释:

/**
     * 获取图片
     *
     * @param fileName 图片缓存的地址
     * @param reWidth  要求的宽度
     * @param reHeight 要求的高度
     */
    private static Bitmap getBitmapFromEX(String fileName, int reWidth,
                                          int reHeight) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(fileName, options);
        // 设置缩放比例,对大图片进行压缩
        options.inSampleSize = getTheBestinSampleSize(options, reWidth, reHeight);
        options.inJustDecodeBounds = false;
        // inPreferredConfig 的默认值是ARGB_8888,改为RGB_565,可以省内存,降低消耗。
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        return BitmapFactory.decodeFile(fileName, options);
    }

以上代码,创建了一个options,由于我们需要获取原Bitmap文件的宽度和高度,所以需要设置options.inJustDecodeBounds = true;为true,true表示的是返回原Bitmap,而原Bitmap我们可以通过outWidth()和outHeight()来获取原Bitmap的宽度和高度。当我们获取了最佳的缩放值的时候options.inSampleSize,我们就不需要放回原Bitmap了,而是返回通过缩放的新的Bitmap了。

2.回收内存

在使用的Activity的onstop或者ondestory中

imageView.setImageDrawable(null);
if (bitmap != null && !bitmap.isRecycled()) {
    bitmap.recycle();
    bitmap = null;
}
System.gc();

附录

Android 多种方式正确的加载图像,有效避免oom
Android有效解决加载大图片时内存溢出的问题
Android加载图片导致内存溢出(Out of Memory异常)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值