OutOfMemoryError using base64 and realmdb when displaying images on android

1

My code what it does is get an image from the gallery or from the camera and convert this image to base64 , then wait in RealmDB , when I want to show the image, I convert it from string to bitmap and I show it in cardview with recyclerview , the detail is that the app becomes slow and then shows the error and then the application stops.

Also in the android monitor I see that the memory consumes too much.

Error:

java.lang.OutOfMemoryError: Failed to allocate a 48771084 byte allocation with 16777216 free bytes and 40MB until OOM

Code:

public class ImageDecode {

    static String imgDecodableString;

    public static String encodeImage(Bitmap bm) {
        ByteArrayOutputStream baos=new  ByteArrayOutputStream();
        bm.compress(Bitmap.CompressFormat.JPEG,100, baos);
        byte [] b=baos.toByteArray();
        try{
            System.gc();
            imgDecodableString= Base64.encodeToString(b, Base64.DEFAULT);
        }catch(Exception e){
            e.printStackTrace();
        }catch(OutOfMemoryError e){
            baos=new  ByteArrayOutputStream();
            bm.compress(Bitmap.CompressFormat.JPEG,50, baos);
            b=baos.toByteArray();
            imgDecodableString=Base64.encodeToString(b, Base64.DEFAULT);
            Log.e("EWN", "Out of memory error catched");
        }
        return imgDecodableString;
    }

    public static Bitmap decodeBase64(String input) {
        byte[] decodedBytes = Base64.decode(input.getBytes(), Base64.DEFAULT);
        return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
    }

    public static String encodeImages(String path) {
        File imagefile = new File(path);
        FileInputStream fis = null;
        try{
            fis = new FileInputStream(imagefile);
        }catch(FileNotFoundException e){
            e.printStackTrace();
        }
        Bitmap bm = BitmapFactory.decodeStream(fis);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bm.compress(Bitmap.CompressFormat.JPEG,100,baos);
        byte[] b = baos.toByteArray();
        try{
            System.gc();
            imgDecodableString = Base64.encodeToString(b, Base64.DEFAULT);
        }catch (OutOfMemoryError e){
            baos = new ByteArrayOutputStream();
            bm.compress(Bitmap.CompressFormat.JPEG,50,baos);
            imgDecodableString = Base64.encodeToString(b, Base64.DEFAULT);
        }
        return imgDecodableString;

    }
}

This way you show the image:

 holder.image.setImageBitmap(ImageDecode.decodeBase64(ProfList.get(position).getImage()));
    
asked by Exbaby 04.05.2017 в 05:09
source

2 answers

1

I see you use

 System.gc();

Something important to remember about Garbage Collector :

  

"GC is smart, in fact, it's smarter than you and it's   autonomous ".

So if you use this:

System.gc();
Runtime.getRuntime().gc();

to try to call the execution of the Garbage Collector , it is not really significant.

You comment that with 3 images you consume about 500MB which is excessive, I recommend you review the images and try to optimize them. What you do is correct

  public static Bitmap decodeBase64(String input) {
        byte[] decodedBytes = Base64.decode(input.getBytes(), Base64.DEFAULT);
        return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
    }

and it should work without problem unless the images are of considerable size. I recommend using GLIDE or PICASSO , but first you must optimize your images.

I recommend this question and the optimization tips:

ViewPager, good resolution an "OutOfMemoryError" image

This is a good question, what is the measure that images should have in an application so that it does not consume a lot of memory and therefore be slow?

Actually the answer is that they must be of an acceptable resolution but a weight in small kbs (something similar to images used in web pages), this to avoid mainly within the application processing and manipulation in memory of the image and consumption of bandwidth that might be unnecessary.

How to make your image light, well you can work with the compression in bytes.

Here is a tutorial: link

The Android SDK has a way to optimize the loading of images, which involves taking a smaller image format by means of the class BitmapFactory :

link

Other recommended considering a previous optimization of the images are the use of two libraries mainly,

GLIDE and PICASSO , whose implementation is simple and very similar.

There are other options but making a benchmark in my opinion are the best options.

Regarding your problem:

  

gallery of images that as I move I get slow the   application.

You must ensure that the image is evicted from the ImageView so that the Garbage Collector can eliminate it from memory, this when it is no longer visible on the screen, because if they are accumulating you could have after a certain time a Java.Lang.OutOfMemoryError , you can do it with:

miImageView.setBackgroundDrawable(null) 
    
answered by 04.05.2017 в 23:41
0

Detects if the image is already in memory to get it from there.

if(imageView != null) {
    ((BitmapDrawable)imageView.getDrawable()).getBitmap().recycle();
}
imageView = (ImageView) view.findViewById(R.id.imageView);
imageView.setImageResource(resID);

See how to load large images efficiently on Android dev

Another way to avoid possible out_of_memory is to use an image load library such as glide

    
answered by 04.05.2017 в 16:35