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