2

I have a Linear layout two which I am adding Image View's programmatically.I am using imageView.setImageBitmap(bitmap); to set the image. And I get a Out of Memory Error. After reading through https://developer.android.com/training/displaying-bitmaps/process-bitmap.html I decided to set the image bitmap in an Async task but I still get the same error.Also this error is not consistent some times I get it sometimes I don't.This is the code for my Async Task class.

class SetImageInAsync extends AsyncTask<String, String, ImageWrapper>{
    ImageView imageView;
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        imageView = new ImageView(DisplayContent.this);
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
        layoutParams.setMargins(16,16,16,16);
        imageView.setLayoutParams(layoutParams);
        imageView.setScaleType(ImageView.ScaleType.FIT_XY);
        web_linearLayout.addView(imageView);

    }

    @Override
    protected ImageWrapper doInBackground(String... params)
    {
        Uri image_uri = Uri.fromFile(new File("/sdcard/rreadyreckoner_images/" + params[0]));
        Bitmap  mBitmap = null;
        try {
            mBitmap = MediaStore.Images.Media.getBitmap(DisplayContent.this.getContentResolver(), image_uri);

        } catch (IOException e) {
            e.printStackTrace();
        }
        ImageWrapper w = new ImageWrapper();
        w.bitmap = mBitmap;
        w.filename = params[0];
        return w;
    }

    @Override
    protected void onPostExecute(final ImageWrapper imgWR) {

        Bundle extras = getIntent().getExtras();
        final String subcategory = extras.getString("subcategory");
        imageView.setAdjustViewBounds(true);
        imageView.setScaleType(TouchImageView.ScaleType.FIT_CENTER);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            imageView.setCropToPadding(false);
        }
        imageView.setImageBitmap(imgWR.bitmap);
        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view)
            {
                Intent intent = new Intent(DisplayContent.this,DisplayImage.class);
                intent.putExtra("filename",imgWR.filename);
                intent.putExtra("subcategory",subcategory);
                startActivity(intent);


            }
        });


    }
}

And this is the error log I get:-

09-27 15:10:07.587 10366-10898/com.inevitable.org.tab_sample E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.inevitable.org.tab_sample, PID: 10366
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:300)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
Caused by: java.lang.OutOfMemoryError
at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
at android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:736)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:712)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:750)
at android.provider.MediaStore$Images$Media.getBitmap(MediaStore.java:830)
at com.inevitable.org.tab_sample.DisplayContent$SetImageInAsync.doInBackground(DisplayContent.java:236)
at com.inevitable.org.tab_sample.DisplayContent$SetImageInAsync.doInBackground(DisplayContent.java:216)
at android.os.AsyncTask$2.call(AsyncTask.java:288)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
at java.lang.Thread.run(Thread.java:841) 

I am new to programming so any help or suggestion is appreciated.Thank you.

AndroidNewBee
  • 744
  • 3
  • 12
  • 36
  • the problem is here in this line **mBitmap = MediaStore.Images.Media.getBitmap(DisplayContent.this.getContentResolver(), image_uri);** check out this http://stackoverflow.com/questions/11381113/mediastore-images-media-getbitmap-and-out-of-memory-error – brahmy adigopula Sep 27 '16 at 10:24
  • Thank you @brahmyadigopula I tried this link http://tutorials-android.blogspot.in/2011/11/outofmemory-exception-when-decoding.html from your suggested link.Now the images are displayed but they are distorted. – AndroidNewBee Sep 27 '16 at 10:42
  • read that blog once again there is **samplesize** property takes a bitmap and reduces its height and width to 20% (1/5) of its original size. The larger the value of inSampleSize N (where N=5 in our example), the more the bitmap is reduced in size. – brahmy adigopula Sep 27 '16 at 10:57
  • Yes I used calculateInSampleSize() from https://developer.android.com/training/displaying-bitmaps/load-bitmap.html and set the width and height of my image to 200 and now the images look pretty descent.Thank you. – AndroidNewBee Sep 27 '16 at 11:18
  • okay happy coding. .bro post your answer and accept it for the next searchers.it will be useful to others. – brahmy adigopula Sep 27 '16 at 11:23
  • Yes I posted the answer. Thank you @brahmyadigopula . Keep up the good work.:) – AndroidNewBee Sep 27 '16 at 11:27

2 Answers2

3

The bitmap is probably too big and causing OOM. It's not a threading issue.

You should read this, it's a good starting point. It's been helpful to many Android developers, including myself.

Loading Large Bitmaps Efficiently

Lev
  • 443
  • 1
  • 4
  • 14
  • @AndroidNewBee Also, the difference between using Bitmap.Config.ARGB_8888 and Bitmap.Config.RGB_565 can be huge and have a big impact on the memory consumption. I suggest read those parts carefully as it helped me a lot. Good luck :) – Lev Sep 27 '16 at 10:16
  • Thank you @Lev. Can you tell me what Resource Id should I provide for the image since I am dynamically adding it from my java code. – AndroidNewBee Sep 27 '16 at 10:28
1

I used the sample code from this example http://tutorials-android.blogspot.in/2011/11/outofmemory-exception-when-decoding.html as suggested by @brahmyadigopula.

// Read bitmap
    public Bitmap readBitmap(Uri selectedImage) {
        Bitmap bm = null;

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



        AssetFileDescriptor fileDescriptor =null;
        try {
            fileDescriptor = this.getContentResolver().openAssetFileDescriptor(selectedImage,"r");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        finally{
            try {
                bm = BitmapFactory.decodeFileDescriptor(fileDescriptor.getFileDescriptor(), null, options);

                // Calculate inSampleSize
                options.inSampleSize = calculateInSampleSize(options,200, 200);

                // Decode bitmap with inSampleSize set
                options.inJustDecodeBounds = false;
                bm = BitmapFactory.decodeFileDescriptor(fileDescriptor.getFileDescriptor(), null, options);


                fileDescriptor.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bm;
    }

And then calculated in sample size using the following code at https://developer.android.com/training/displaying-bitmaps/load-bitmap.html as suggested by @Lev.

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 / 2;
        final int halfWidth = width / 2;

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

And used it as follows :-

 Uri image_uri = Uri.fromFile(new File("/sdcard/rreadyreckoner_images/" + params[0]));

            Bitmap mBitmap = readBitmap(image_uri);

Thank you @Lev and @brahmyadigopula for your guidance.Keep up the good work.

AndroidNewBee
  • 744
  • 3
  • 12
  • 36