I am using Image Compression method from this link it working fine if i compress single image but as soon as i give this method multiple images to compress in STRICT MODE app get crashed at ExifInterface exif = new ExifInterface(filePath);
with logcat all i can understand something is not close which might cause leaks. I tried lots of things but none work it crashed everytime i give this method multiple images.
Image Compression Method
public static String compressImage(Uri imageUri, boolean multiple, Context context) {
String filePath = imageUri.getPath();
Log.d(TAG,"File Path "+filePath);
Bitmap scaledBitmap = null;
BitmapFactory.Options options = new BitmapFactory.Options();
// by setting this field as true, the actual bitmap pixels are not loaded in the memory. Just the bounds are loaded. If
// you try the use the bitmap here, you will get null.
options.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeFile(filePath, options);
Log.d(TAG,"Bitmap value "+bmp);
int actualHeight = options.outHeight;
int actualWidth = options.outWidth;
Log.d(TAG,"Actual Height and Width "+actualHeight+" "+actualWidth);
// max Height and width values of the compressed image is taken as 816x612
float maxHeight = 816.0f;
float maxWidth = 612.0f;
float imgRatio = actualWidth / actualHeight;
float maxRatio = maxWidth / maxHeight;
// width and height values are set maintaining the aspect ratio of the image
if (actualHeight > maxHeight || actualWidth > maxWidth) {
if (imgRatio < maxRatio) { imgRatio = maxHeight / actualHeight;
actualWidth = (int) (imgRatio * actualWidth);
actualHeight = (int) maxHeight;
} else if (imgRatio > maxRatio) {
imgRatio = maxWidth / actualWidth;
actualHeight = (int) (imgRatio * actualHeight);
actualWidth = (int) maxWidth;
} else {
actualHeight = (int) maxHeight;
actualWidth = (int) maxWidth;
}
}
// setting inSampleSize value allows to load a scaled down version of the original image
options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight);
// inJustDecodeBounds set to false to load the actual bitmap
options.inJustDecodeBounds = false;
// this options allow android to claim the bitmap memory if it runs low on memory
options.inPurgeable = true;
options.inInputShareable = true;
options.inTempStorage = new byte[16 * 1024];
try {
// load the bitmap from its path
bmp = BitmapFactory.decodeFile(filePath, options);
} catch (OutOfMemoryError exception) {
exception.printStackTrace();
}
try {
scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight,Bitmap.Config.ARGB_8888);
} catch (OutOfMemoryError exception) {
exception.printStackTrace();
}
float ratioX = actualWidth / (float) options.outWidth;
float ratioY = actualHeight / (float) options.outHeight;
float middleX = actualWidth / 2.0f;
float middleY = actualHeight / 2.0f;
Matrix scaleMatrix = new Matrix();
scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);
Canvas canvas = new Canvas(scaledBitmap);
canvas.setMatrix(scaleMatrix);
canvas.drawBitmap(bmp, middleX - bmp.getWidth() / 2, middleY - bmp.getHeight() / 2, new Paint(Paint.FILTER_BITMAP_FLAG));
// check the rotation of the image and display it properly
try {
ExifInterface exif = new ExifInterface(filePath);
int orientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION, 0);
Log.d("EXIF", "Exif: " + orientation);
Matrix matrix = new Matrix();
if (orientation == 6) {
matrix.postRotate(90);
Log.d("EXIF", "Exif: " + orientation);
} else if (orientation == 3) {
matrix.postRotate(180);
Log.d("EXIF", "Exif: " + orientation);
} else if (orientation == 8) {
matrix.postRotate(270);
Log.d("EXIF", "Exif: " + orientation);
}
scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0,
scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix,
true);
String filename = getFilename();
FileOutputStream out = new FileOutputStream(filename);
// write the compressed bitmap at the destination specified by filename.
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
return filename;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Calling image compression method
for (int i = 0; i <size ; i++) {
String compressImage = App_Functions.compressImage(Uri.parse(attachmentPath.get(i).getImagePath()),true,this);
imageArray.add(compressImage);
}
Error Log
02-17 17:55:28.124 21641-21649/com.Example.test E/StrictMode: A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.
java.lang.Throwable: Explicit termination method 'close' not called
at dalvik.system.CloseGuard.open(CloseGuard.java:180)
at java.io.FileInputStream.<init>(FileInputStream.java:78)
at java.io.FileInputStream.<init>(FileInputStream.java:103)
at android.media.ExifInterface.loadAttributes(ExifInterface.java:1338)
at android.media.ExifInterface.<init>(ExifInterface.java:1057)
at com.Example.App_Functions.compressImage(App_Functions.java:685)
at com.Example.Navigation_Drawer.onBottomSheetClicked(Navigation_Drawer.java:851)
at com.Example.mainScreenFragments.BottomSheet.onClick(BottomSheet.java:410)
at android.view.View.performClick(View.java:5204)
at android.view.View$PerformClick.run(View.java:21153)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
02-17 17:55:28.124 21641-21649/com.Example.test W/System.err: StrictMode VmPolicy violation with POLICY_DEATH; shutting down.
02-17 17:55:28.124 21641-21649/com.Example.test I/Process: Sending signal. PID: 21641 SIG: 9
When it comes to ExifInterface
, always use one from a library, for a few reasons:
Devices older than Android 7.0 may have a security flaw in the framework copy of ExifInterface
The API changed over the years, and the library will give you a consistent API and functionality regardless of Android version
The framework team does not always test their code with StrictMode
enabled, and device manufacturers make similar mistakes