如何在Android中加载大图像并避免内存不足错误?

dcp*_*450 16 android bitmap out-of-memory

我正在开发一个使用大图像(1390×870:150kb - 50kb)的应用程序.当我点击触发器/ ImageView时,我正在添加图像.

在某一点上,我得到一个内存不足的错误:

java.lang.OutOfMemoryError
E/AndroidRuntime(23369): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
E/AndroidRuntime(23369): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:613)
E/AndroidRuntime(23369): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:378)
Run Code Online (Sandbox Code Playgroud)

为了调整图像大小,我正在这样做:

Bitmap productIndex = null;
final String imageLoc = IMAGE_LOCATION;
InputStream imageStream;
try {
     imageStream = new FileInputStream(imageLoc);
     productIndex = decodeSampledBitmapFromResource(getResources(), imageLoc, 400, 400);

     productIV.setImageBitmap(productIndex);
     } catch (FileNotFoundException e1) {
          // TODO Auto-generated catch block
          e1.printStackTrace();
     }
}


public static Bitmap decodeSampledBitmapFromResource(Resources res, String resId, int reqWidth, int reqHeight) {

// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(resId, options);

// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(resId, options);
}

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;

if (height > reqHeight || width > reqWidth) {

    final int halfHeight = height / 3;
    final int halfWidth = width / 3;

    // Calculate the largest inSampleSize value that is a power of 2 and keeps both
    // height and width larger than the requested height and width.
    while ((halfHeight / inSampleSize) > reqHeight
            && (halfWidth / inSampleSize) > reqWidth) {
        inSampleSize *= 2;
    }
}

return inSampleSize;
}
Run Code Online (Sandbox Code Playgroud)

我采用这种方式调整大小以节省Android Docs的空间: 有效地加载大位图

根据日志,这就像是方法的罪魁祸首decodeSampledBitmapFromResource:

return BitmapFactory.decodeFile(resId, options);
Run Code Online (Sandbox Code Playgroud)

-----编辑-----以下是我将每个项目添加到FrameLayout的方法.

for(int ps=0;ps<productSplit.size();ps++){
    //split each product by the equals sign
    List<String> productItem = Arrays.asList(productSplit.get(ps).split("="));

    String tempCarID = productItem.get(0);
    tempCarID = tempCarID.replace(" ", "");
    if(String.valueOf(carID).equals(tempCarID)){

        ImageView productIV = new ImageView(Configurator.this);
        LayoutParams productParams = new LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        productIV.setId(Integer.parseInt(partIdsList.get(x)));
        productIV.setLayoutParams(productParams);

        final String imageLoc = productItem.get(2);

        InputStream imageStream;
        try {
            imageStream = new FileInputStream(imageLoc);
            productIndex = decodeSampledBitmapFromResource(getResources(), imageLoc, 400, 400);
            productIV.setImageBitmap(productIndex);
        } catch (FileNotFoundException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        productLayers.addView(productIV);

    }
}
Run Code Online (Sandbox Code Playgroud)

Bjö*_*röm 30

您可以使用另一个bitmap-config来大幅减小图像的大小.默认为RGB-config ARGB8888,这意味着使用了四个8位通道(红色,绿色,蓝色,alhpa).Alpha是位图的透明度.这占用了大量的内存 - 图像化X 4.因此,如果图像大小为4百万像素16兆字节将立即在堆上分配 - 快速耗尽内存.

相反 - 使用RGB_565在某种程度上会降低质量 - 但为了弥补这一点,你可以抖动图像.

所以 - 对你的方法decodeSampledBitmapFromResource - 添加以下代码片段:

 options.inPreferredConfig = Config.RGB_565;
 options.inDither = true;
Run Code Online (Sandbox Code Playgroud)

在你的代码中:

 public static Bitmap decodeSampledBitmapFromResource(Resources res, String resId, int    reqWidth, int reqHeight) {

 // First decode with inJustDecodeBounds=true to check dimensions
 final BitmapFactory.Options options = new BitmapFactory.Options();
 options.inJustDecodeBounds = true;
 BitmapFactory.decodeFile(resId, options);

 // Calculate inSampleSize
 options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

 // Decode bitmap with inSampleSize set
 options.inJustDecodeBounds = false;
 options.inPreferredConfig = Config.RGB_565;
 options.inDither = true;
 return BitmapFactory.decodeFile(resId, options);
 }
Run Code Online (Sandbox Code Playgroud)

参考文献:

http://developer.android.com/reference/android/graphics/Bitmap.Config.html#ARGB_8888


ser*_*rge 25

如果您没有将图像放在正确的文件夹中,则S4等高分辨率设备通常会耗尽内存drawable-xxhdpi.您也可以将图像放入drawable-nodpi.如果你的图像只是因为你的图像drawable会缩放图像,认为图像是为低分辨率设计的,那么它就会用尽memorey .