在Android Studio中使用ImageView避免OutOfMemory错误

时间:2016-07-07 19:14:47

标签: android android-layout android-bitmap

我使用RecyclerView和CardView进行布局,并希望在屏幕上显示横跨4张卡片的水印。我将水印图像切割成4张单独的图像,每张图片一张(每张图片已经有我想要显示的尺寸)。为了显示图像,我在每个卡的.xml文件中使用ImageView:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cardview"
    android:layout_width="415dp"
    android:layout_height="89dp"
    android:layout_marginTop="0dp"
    android:elevation="100dp"
    card_view:cardBackgroundColor="#ffffff">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:src="@drawable/watermark_card1"
            android:scaleType="centerCrop" />
        .
        .
        .
    </RelativeLayout>
</android.support.v7.widget.CardView>

这个工作正常,而我只加载4个图像中的2个,但是当我加载第3个图像时,我收到以下错误:

java.lang.OutOfMemoryError:无法分配带有4194304个空闲字节的210446976字节分配和101MB直到OOM

我认为这是因为图像都非常大(521K,976K,611K和933K),我想知道如何使用更少的内存并避免出现OutOfMemory错误。任何建议都将不胜感激,谢谢!

5 个答案:

答案 0 :(得分:1)

您必须调整图像质量或降低图像质量。并使用像volly或picasso这样的图像库。这个库可以解决与图像有关的各种问题。

答案 1 :(得分:1)

在AndroidManifest.xml文件中,在应用程序标记内添加以下行

android:largeHeap="true"

但是,请记住这只会增加堆内存并为您提供解决方案。但是,这不是最好的做法。你应该正确回收你的记忆。

参考链接

Strange out of memory issue while loading an image to a Bitmap object

Android: convert Immutable Bitmap into Mutable

答案 2 :(得分:0)

您可以在使用BitmapFactory创建图像时对图像进行缩减采样。您只需将图像包含为资源并获取输入流,然后创建缩减采样的Bitmap对象。这样,您可以根据设备,屏幕大小,可用内存等来决定图像的大小。创建Bitmap对象后,使用ImageView.setImageBitmap()将其设置到图像视图中。以下是下采样方法的示例 -

public static Bitmap decodeBitmap(InputStream decodeStream, byte[] decodeArray) throws IOException
{
    BitmapFactory.Options   options = new BitmapFactory.Options();
    Bitmap                  bitmap = null;
    boolean                 useStream = ((decodeStream != null) ? true : false);
    int                     actualFileSize;

    // get the decoded object size without actually decoding and creating the object
    options.inJustDecodeBounds = true;
    if (useStream)
        BitmapFactory.decodeStream(decodeStream, null, options);
    else
        BitmapFactory.decodeByteArray(decodeArray, 0, decodeArray.length, options);
    actualFileSize = options.outWidth * options.outHeight * 4;

    if (useStream)
        decodeStream.reset(); // reset the data - we assume the underlying input stream implements reset() in a
                              // way that will not throw an exception in the case where the stream is not marked

    if (actualFileSize > MAX_BYTES)
    {   
        options = new BitmapFactory.Options(); // recreate the options to get the defaults back

        if (actualFileSize/4 <= MAX_BYTES)
            options.inSampleSize = 2; // a sample size of 2 has 1/4th the pixels
        else if(actualFileSize/16 <= MAX_BYTES)
            options.inSampleSize = 4; // a sample size of 4 has 1/16th the pixels
        else
            options.inSampleSize = 8; // if it is still too big, attempt a sample size of 8 (1/64th the pixels)

        if (useStream)
            bitmap = BitmapFactory.decodeStream(decodeStream, null, options); 
        else
            bitmap = BitmapFactory.decodeByteArray(decodeArray, 0, decodeArray.length, options);
    }
    else
    {
        if (useStream)
            bitmap = BitmapFactory.decodeStream(decodeStream);
        else
            bitmap = BitmapFactory.decodeByteArray(decodeArray, 0, decodeArray.length, null);
    }
    return bitmap;
}

最后,当您在代码中加载图像时,我发现在每次调用decodeStream()之前和之后强制进行垃圾收集(通过System.gc())会很有帮助。完成Bitmap对象后,使用Bitmap.recycle()显式处理它们的内存。在Android上使用大位图进行内存管理可能会有点毛茸茸 - 这里有一些其他的建议 - https://developer.android.com/training/displaying-bitmaps/manage-memory.html

希望这有帮助。

答案 3 :(得分:0)

OutOfMemory错误意味着您的图片尺寸很大,因此要么降低图像质量要么使用图像库以便缓存图像,如果它仍然没有帮助,那么在清单中的应用程序标记中使bigheap = true文件。

答案 4 :(得分:0)

要避免此错误,您必须遵循此链接中的建议: https://developer.android.com/training/displaying-bitmaps/load-bitmap.html (并查看接下来的两个教程)。

但最简单的方法是使用一个受欢迎的图书馆(如其中一个答案所述) - 例如毕加索(http://square.github.io/picasso/)。