1

BitmapFactory.decodeFile causes outOfMemoryError only when I choose the image from the phone gallery, not when I choose the image from taking the photo with the camera intent. I actually avoid using decodeFile when using the camera intent. Can I use that same approach when choosing from the gallery (getting data from the intent)? Here is my code for getting the image in both ways:

If image was chosen from the device' gallery:

if (requestCode == 1) 
              {
                  if (intent != null && resultcode == RESULT_OK) 
                  {
                  ImageHelper ih = new ImageHelper();
                  mProfilePicPath = ih.getSelectedImageFilePathFromGallery(this, intent);
                  Bitmap portraitPhoto = ih.getChosenImageFromGallery(mProfilePicPath);
                    try{
                        ih.saveImage("Profile pics", portraitPhoto, this);

ImageHelper.getChosenImageFromGallery:

public Bitmap getChosenImageFromGallery(String imagePath) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(imagePath, options);
        options.inSampleSize = DressingRoomActivity.calculateInSampleSize(options, 500, 500);
        options.inJustDecodeBounds = false;
        Bitmap portraitPhoto = ImageHelper.convertToPortraitOrientation(options, imagePath);
        return portraitPhoto;
    }

If image was chosen by taking photo using camera:

else if ((requestCode == CAMERA_REQUEST)&& (resultcode == Activity.RESULT_OK)){
                Bundle extras = intent.getExtras();
                Uri selectedImage = intent.getData();
                if (extras != null) {
                    ImageHelper ih = new ImageHelper();
                    mProfilePicPath = ih.getFilePathFromCameraPhoto(this, selectedImage);
                    Bitmap photo = (Bitmap) intent.getExtras().get("data");
                    try{
                    ih.saveImage("Profile pics", photo, this);

As you can see, to grab the image from the gallery and get the Bitmap from it, I have to create the Bitmap to be only 500 x 500 pixels with this code options.inSampleSize = DressingRoomActivity.calculateInSampleSize(options, 500, 500); Otherwise it causes an outOfMemoryError on the line Bitmap bmp = BitmapFactory.decodeFile(path, options); Which is in the ImageHelper.convertToPortraitOrientation(options, imagePath); method. This means the user gets AS IS quality in their image from the camera, and 500px quality from their image in the gallery.

My questions: 1) Is there any way to not make my image quality 500px when choosing from gallery? Like avoid this line somehow: Bitmap bmp = BitmapFactory.decodeFile(path, options); or some other way?

2) With the gallery I had to convert to portrait which is only a minor annoyance but why is that? It flips the photo sideways if I don't.

user3164083
  • 1,053
  • 6
  • 18
  • 35

2 Answers2

1

Here is a complete tuto on how to Display Bitmaps Efficiently from the official doc. I had the same problem as you. What i did was to read and understand all the lessons from the given page before returning back to my codes. Try that, you will get things clearer in your head.

Edit

Your app is crashing because you are running the Bitmap.decode() method in the main thread. Use another thread (with a simple AsyncTask) to do that.

As i said before, there is a nice tuto on how to handle bitmap off UI Thread

S.Thiongane
  • 6,883
  • 3
  • 37
  • 52
  • After reading that, I think most of those approaches are for performance. I'm just looking at not crashing the memory for now. I think the only fix there was making the image smaller which I am already doing :/ It said Caching can use more memory. It also suggested not using WeakReference. Not really sure what to do as I need an output image of same quality as input. It's a photo editor app. – user3164083 Jan 15 '14 at 23:55
  • see my edit. `I'm just looking at not crashing the memory for now` : you have to handle bitmaps nicely to avoid app crashing. That's why i provided the link above. Read the tutos, try to understand and come back for any question. – S.Thiongane Jan 16 '14 at 00:24
  • Thanks, however i'm fairly sure from research that asynctask is for making it load faster, and will not address the outofmemoryerror. It will take the same memory in the worker thread. I have just looked at other peoples similar questions and the answer is consistantly "make the image smaller". Unfortunately I think this is my only option – user3164083 Jan 16 '14 at 00:33
  • You put the bitmap decoding job in an `AsyncTask` to avoid potential long running I/O jobs (read file etc), not to save you from OOM (allocations). – Magnus Jan 16 '14 at 20:34
0

There is 2 possible solutions to overcome outOfMemory exception:

Solution 1: you should use weakReference variables like.

WeakReference<Bitmap> weakReferenceBitmap=new
             WeakReference<Bitmap>(bitmap);

GC clear weakReference variable more efficient as compare to other.

Solution2: you can use largeHeap property in your manifest to require more heap space then normal.

<application
        android:largeHeap="true">

</application>

I will not recommend you the 2nd solution, but it works :)

Hope it will help :)

Ahmad Raza
  • 2,850
  • 1
  • 21
  • 37
  • Thanks! largeHeap sounds like it might not be usable on low quality Android devices. Will WeakReference work in this method if I edit it? `public static Bitmap createRotatedBitmap(Bitmap bm, float degree) { Bitmap bitmap = null; if (degree != 0) { Matrix matrix = new Matrix(); matrix.preRotate(degree); bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true); } return bitmap; }` – user3164083 Jan 15 '14 at 22:15
  • WeakRefrence will work! But if you are doing too much decoding then you should use largeHeap option. Don't worry, app will work on low quality android devices as well. – Ahmad Raza Jan 15 '14 at 22:20
  • Thanks :) This app is all about images. There is a lot of decoding. So I will use largeHeap. Should I also use WealReference, in your opinion? – user3164083 Jan 15 '14 at 22:24
  • Yes, please use both, because largeHeap is only to get more heap then normal, But we should manage that heap efficiently. – Ahmad Raza Jan 15 '14 at 22:25
  • Thanks. I will mark as the answer once I have confirmed it works, first I want to research WeakReference to ensure I use it correctly. At some point I must convert from WeakReference to a real Bitmap, yes? – user3164083 Jan 15 '14 at 22:30
  • no, you don't need to convert weakReference to real bitmap. Because when you call weakReference.get().. it will return the real bitmap. Weak Reference is like a box, you can put your object inside it. Please see documentation: http://developer.android.com/reference/java/lang/ref/WeakReference.html – Ahmad Raza Jan 15 '14 at 22:34
  • 1
    @user3164083 Here is why you should NOT go with largeHeap as the first resort to OOM problems: [largeHeap pitfalls](http://stackoverflow.com/questions/11275650/how-to-increase-heap-size-of-an-android-application/11275704#11275704) – Magnus Jan 17 '14 at 09:10
  • @Magnus Thanks. I have made the images 500px for now. It still looks ok, but not amazing. I don't kill off my activities when I go to a new activity. Am I supposed to to free up memory? – user3164083 Jan 18 '14 at 06:36