Android StrictMode 策略:已在附加堆栈跟踪中获取资源但从未释放错误

Android StrictMode Policy: A resource was acquired at attached stack trace but never released Error

我正在使用此 link 中的图像压缩方法,如果我压缩单个图像,它工作正常,但是一旦我使用此方法在严格模式下压缩多个图像,应用程序就会在 ExifInterface exif = new ExifInterface(filePath); 处崩溃logcat 所有我能理解的东西没有关闭,这可能会导致泄漏。我尝试了很多东西,但是 none 每次我给这个方法多张图片时它都会崩溃。

图片压缩方式

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

调用图像压缩方法

for (int i = 0; i <size ; i++) {
                        String compressImage = App_Functions.compressImage(Uri.parse(attachmentPath.get(i).getImagePath()),true,this);
                        imageArray.add(compressImage); 

                    }

错误日志

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

当谈到 ExifInterface 时,总是使用图书馆中的一个,原因如下:

  • 设备早于 Android 7.0 may have a security flaw in the framework copy of ExifInterface

  • 这些年来 API 发生了变化,无论 Android 版本如何

    [,库都会为您提供一致的 API 和功能=26=]
  • 框架团队并不总是在启用 StrictMode 的情况下测试他们的代码,设备制造商也会犯类似的错误