Simran
Simran

Reputation: 21

Avoiding an OutOfMemory Error using ImageView in Android Studio

I'm using RecyclerView and CardView for my layout and want to display a watermark which spans across 4 cards on the screen. I've chopped up the watermark image into 4 separate images, one for each card (each image already has the dimensions I want it to be displayed with). To display the images, I am using ImageView inside of each card's .xml file as such:

<?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>

This works fine while I am only loading 2 out of the 4 images, but when I load the 3rd one, I get the following error:

java.lang.OutOfMemoryError: Failed to allocate a 210446976 byte allocation with 4194304 free bytes and 101MB until OOM

I believe that this is because the images are all very large (521K, 976K, 611K, and 933K) and I am wondering what I could do to use less memory and avoid the OutOfMemory Error. Any advice would be appreciated, thanks!

Upvotes: 1

Views: 692

Answers (5)

Dmitriy
Dmitriy

Reputation: 517

To avoid this error you have to follow recommendations from this link: https://developer.android.com/training/displaying-bitmaps/load-bitmap.html (and look the next two tutorials).

But the easiest way to do it is use one of popular libraries (as were said in one of the answers) - e.g. Picasso (http://square.github.io/picasso/).

Upvotes: 0

ubhusri
ubhusri

Reputation: 52

OutOfMemory error means your images are large in size, so either you decrease quality of the image or use an image library so that it caches your image and also if it still doesnt help then make largeheap=true in your application tag in manifest file.

Upvotes: 0

madhan kumar
madhan kumar

Reputation: 1608

In AndroidManifest.xml file, inside the application tag add the below line

android:largeHeap="true"

But, remember this only increase the heap memory and give you solution. But, it's not the best practice. You should recycle your memory properly.

Refer the links

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

Android: convert Immutable Bitmap into Mutable

Upvotes: 1

tpankake
tpankake

Reputation: 366

You can downsample the image as you create it using BitmapFactory. You would just include the images as assets and get an input stream to them, then create downsampled Bitmap objects. This way, you can decide how large you want the images to be based on the device, screen size, memory available, etc. After you create the Bitmap object, use ImageView.setImageBitmap() to set it into your image view. Below is an example of a downsampling method -

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;
}

Finally, as you're loading your images in code, I have found it helpful to force garbage collections (via System.gc()) before and after each call do decodeStream(). When you are done with the Bitmap objects, dispose of their memory explicitly using Bitmap.recycle(). Memory management with large bitmaps on Android can get a little hairy - there are some other suggestions here - https://developer.android.com/training/displaying-bitmaps/manage-memory.html

Hope this helps.

Upvotes: 0

hanbumpark
hanbumpark

Reputation: 233

you must resize or reduce quality of image. and use image library like volly or picasso. this library can solve variety problem relate with image.

Upvotes: 1

Related Questions