0

In my application I am capturing images and creating bitmap, below is code

byte[] data;
options=new BitmapFactory.Options();// Create object of bitmapfactory's option method for further option use
options.inPurgeable = true;

cleaned=BitmapFactory.decodeByteArray(data, 0, data.length,options);

this is working fine in Kitkat and below and I am able to captured more than 30 images, but in Lollipop when I captured 19 images No issue, after that app crashed with OOM.

can any one give me solution, How to handle the OOM in Lollipop.

I am Capturing the Image ByCalling the ImageCleanupTask with follwoing code

private Camera.Parameters previewParams=null;

previewParams=camera.getParameters();

        Camera.Parameters pictureParams=camera.getParameters();
        Camera.Size pictureSize=
            xact.host.getPictureSize(xact, pictureParams);
        
        System.out.println("Picture Size : "+pictureSize.width+ " X "+pictureSize.height);

        //pictureParams.setPictureSize(pictureSize.width,pictureSize.height);
        List<Camera.Size> sizes = pictureParams.getSupportedPreviewSizes();
        for(Camera.Size s:sizes)
        {
         System.out.println(s.height+"///"+s.width);
        }
        Camera.Size cs = sizes.get(0);
        pictureParams.setPreviewSize(cs.width, cs.height);
        //pictureParams.setPictureSize(320,460);
        
        pictureParams.setPictureFormat(ImageFormat.JPEG);

        if (xact.flashMode != null) {
          pictureParams.setFlashMode(xact.flashMode);
        }

        if (!onOrientationChange.isEnabled()) {
          setCameraPictureOrientation(pictureParams);
        }

        camera.setParameters(xact.host.adjustPictureParameters(xact,
                                                               pictureParams));
        xact.cameraView=this;

        postDelayed(new Runnable() {
          @Override
          public void run() {
            try {
             if(picturetransactionCallBack!=null)
              picturetransactionCallBack=null;
             picturetransactionCallBack=new PictureTransactionCallback(xact);
              camera.takePicture(xact, null,
                picturetransactionCallBack);
              picturetransactionCallBack=null;
            }
            catch (Exception e) {
              android.util.Log.e(getClass().getSimpleName(),
                                 "Exception taking a picture", e);
              // TODO get this out to library clients
            }
          }
        }, 1000);


private class PictureTransactionCallback implements
      Camera.PictureCallback {
    PictureTransaction xact=null;

    PictureTransactionCallback(PictureTransaction xact) {
      this.xact=xact;
    }

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
      camera.setParameters(previewParams);

      if (data != null) {
       if(imageCleanUpTask!=null)
        imageCleanUpTask=null;
       imageCleanUpTask=  new ImageCleanupTask(getContext(), data, cameraId, xact);
       imageCleanUpTask.start();
       data=null;
      }

      if (!xact.useSingleShotMode()) {
        startPreview();
      }
    }
  }

And this is my ImageCleanupTask Thread.

public class ImageCleanupTask extends Thread {
  private byte[] data;
  private int cameraId;
  private PictureTransaction xact=null;
  private boolean applyMatrix=true;
 static BitmapFactory.Options options;
 static Matrix matrix=null;
 static Bitmap cleaned=null;
 static ExifInterface exif=null;
 static ActivityManager am;
 static Bitmap original;
 public ImageCleanupTask(Context ctxt, byte[] data, int cameraId,
                   PictureTransaction xact) {
    this.data=data;
    this.cameraId=cameraId;
    this.xact=xact;

    float heapPct=(float)data.length / calculateHeapSize(ctxt);

    applyMatrix=(heapPct < xact.host.maxPictureCleanupHeapUsage());
    ActivityManager mgr = (ActivityManager)ctxt.getSystemService(Context.ACTIVITY_SERVICE);
 ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo();
 mgr.getMemoryInfo(info);
 System.out.println("Available ememory for app: "+info.availMem/(1024*1024));

  //  Double available = new Double(Debug.getNativeHeapSize())/1048576;
     options=new BitmapFactory.Options();// Create object of bitmapfactory's option method for further option use
    options.inPurgeable = true;
  }

  @Override
  public void run() {
    Camera.CameraInfo info=new Camera.CameraInfo();

    Camera.getCameraInfo(cameraId, info);

   

    if (applyMatrix) {
      if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
        if (xact.host.getDeviceProfile().portraitFFCFlipped()
            && (xact.displayOrientation == 90 || xact.displayOrientation == 270)) {
          matrix=flip(new Matrix());
        }
        else if (xact.mirrorFFC()) {
          matrix=mirror(new Matrix());
        }
      }

      try {
        int imageOrientation=0;

        if (xact.host.getDeviceProfile().useDeviceOrientation()) {
          imageOrientation=xact.displayOrientation;
        }
        else {
          exif=new ExifInterface();
          exif.readExif(data);

          Integer exifOrientation=
              exif.getTagIntValue(ExifInterface.TAG_ORIENTATION);

          if (exifOrientation != null) {
            if (exifOrientation == 6) {
              imageOrientation=90;
            }
            else if (exifOrientation == 8) {
              imageOrientation=270;
            }
            else if (exifOrientation == 3) {
              imageOrientation=180;
            }
            else if (exifOrientation == 1) {
              imageOrientation=0;
            }
            else {
              // imageOrientation=
              // xact.host.getDeviceProfile().getDefaultOrientation();
              //
              // if (imageOrientation == -1) {
              // imageOrientation=xact.displayOrientation;
              // }
            }
          }
        }
        if (imageOrientation != 0) {
          matrix=
              rotate((matrix == null ? new Matrix() : matrix),
                     imageOrientation);
        }
      }
      catch (IOException e) {
        Log.e("CWAC-Camera", "Exception parsing JPEG", e);
        // TODO: ripple to client
      }
      if (matrix != null) {
       if( options==null){
        options=new BitmapFactory.Options();// Create object of bitmapfactory's option method for further option use
          options.inPurgeable = true;
       }
         original=
            BitmapFactory.decodeByteArray(data, 0, data.length,options);

        cleaned=
            Bitmap.createBitmap(original, 0, 0, original.getWidth(),
                                original.getHeight(), matrix, true);
        original.recycle();
      }
    }
    if (xact.needBitmap) {
      if (cleaned == null) {
       if( options==null){
        options=new BitmapFactory.Options();// Create object of bitmapfactory's option method for further option use
          options.inPurgeable = true;
       }
        cleaned=BitmapFactory.decodeByteArray(data, 0, data.length,options);
      }

      xact.host.saveImage(xact, cleaned);
    }
    if (xact.needByteArray) {
      if (matrix != null) {
        ByteArrayOutputStream out=new ByteArrayOutputStream();

        // if (exif == null) {
        cleaned.compress(Bitmap.CompressFormat.JPEG, 100, out);
        // }
        // else {
        // exif.deleteTag(ExifInterface.TAG_ORIENTATION);
        //
        // try {
        // exif.writeExif(cleaned, out);
        // }
        // catch (IOException e) {
        // Log.e("CWAC-Camera", "Exception writing to JPEG",
        // e);
        // // TODO: ripple to client
        // }
        // }

        data=out.toByteArray();

        try {
         out.flush();
          out.close();
        }
        catch (IOException e) {
          Log.e(CameraView.TAG, "Exception in closing a BAOS???", e);
        }
      }

      xact.host.saveImage(xact, data);
    }
    try{
     if(cleaned!=null)
   cleaned.recycle();
    data=null;
    System.gc();
    }catch(Exception e)
    {
     e.printStackTrace();
    }
  }

  // from http://stackoverflow.com/a/8347956/115145

  private Matrix mirror(Matrix input) {
    float[] mirrorY= { -1, 0, 0, 0, 1, 0, 0, 0, 1 };
    Matrix matrixMirrorY=new Matrix();

    matrixMirrorY.setValues(mirrorY);
    input.postConcat(matrixMirrorY);

    return(input);
  }

  private Matrix flip(Matrix input) {
    float[] mirrorY= { -1, 0, 0, 0, 1, 0, 0, 0, 1 };
    Matrix matrixMirrorY=new Matrix();

    matrixMirrorY.setValues(mirrorY);
    input.preScale(1.0f, -1.0f);
    input.postConcat(matrixMirrorY);

    return(input);
  }

  private Matrix rotate(Matrix input, int degree) {
    input.setRotate(degree);

    return(input);
  }

  @TargetApi(Build.VERSION_CODES.HONEYCOMB)
  private  int calculateHeapSize(Context ctxt) {
   am=
        (ActivityManager)ctxt.getSystemService(Context.ACTIVITY_SERVICE);
    int memoryClass=am.getMemoryClass();

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
      if ((ctxt.getApplicationInfo().flags & ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
        memoryClass=am.getLargeMemoryClass();
      }
    }

    return(memoryClass * 1048576); // MB * bytes in MB
  }
  }
After capturing the Image I added bitmap to Image for Editing the Image by this line. xact.host.saveImage(xact, cleaned);

In Nexus7(Kitkat) I able to take more images and editable that images,but when I run the app in Samsung Tablet(Lollipop) app crashed.

For every capture Image the log is 05-15 15:52:43.204: I/art(4858): Explicit concurrent mark sweep GC freed 2656(235KB) AllocSpace objects, 2(25MB) LOS objects, 8% free, 173MB/189MB, paused 566us total 34.267ms 05-15 15:52:43.229: I/art(4858): Explicit concurrent mark sweep GC freed 10(384B) AllocSpace objects, 0(0B) LOS objects, 8% free, 173MB/189MB, paused 554us total 24.596ms

here 173MB/189MB showing the used heap size and it 20MB to 30MB incresing for every captured image, when it reached 512 app crashed in Samsung

Chandramouli
  • 76
  • 1
  • 6
  • Can you post logcat? – hrskrs May 15 '15 at 09:20
  • 1
    Can you please be more specific? Show us more relevant code, how you store the bitmaps in memory which devices you use to test your app. Nobody can diagnose a problem if you just tell us that there is one - it could have any number of reason - you have to give use more context. – Xaver Kapeller May 15 '15 at 09:32
  • Once received this log " Clamp target GC heap from 514MB to 512MB " App crashed and below is my logcat result Failed to allocate a 23970828 byte allocation with 14165316 free bytes and 13MB until OOM at dalvik.system.VMRuntime.newNonMovableArray(Native Method) at android.graphics.Bitmap.nativeCreate(Native Method) at android.graphics.Bitmap.createBitmap(Bitmap.java:939) at android.graphics.Bitmap.createBitmap(Bitmap.java:912) at android.graphics.Bitmap.createBitmap(Bitmap.java:843) at com.app.homepad.camera.android.ImageCleanupTask.run(ImageCleanupTask.java:128) – Chandramouli May 15 '15 at 10:40
  • I was taken code from this link https://github.com/commonsguy/cwac-camera – Chandramouli May 15 '15 at 10:42

0 Answers0