android - "Can' t compress a recycled bitmap”单个设备异常

标签 android exception bitmap imageview

我的 HTC Wildfire S 设备遇到了大问题。我的应用程序使用图像 uri 启动第二个 Activity ,用户可以旋转图像,然后将其保存并返回到主 Activity 。问题出在 HTC 上,只有第一张照片会被返回,第二张照片会导致应用程序崩溃并出现以下错误:

java.lang.IllegalStateException: 无法压缩回收位图 在 android.graphics.Bitmap.checkRecycled(Bitmap.java:372) 在 android.graphics.Bitmap.compress(Bitmap.java:799) 在 zapytaj.hot.or.not.ImageRotator.end(ImageRotator.java:151) 在 zapytaj.hot.or.not.ImageRotator$RotatorClass.onClick(ImageRotator.java:80) 在 android.view.View.performClick(View.java:2532) 在 android.view.View$PerformClick.run(View.java:9293) 在 android.os.Handler.handleCallback(Handler.java:587) 在 android.os.Handler.dispatchMessage(Handler.java:92) 在 android.os.Looper.loop(Looper.java:150) 在 android.app.ActivityThread.main(ActivityThread.java:4277) 在 java.lang.reflect.Method.invokeNative( native 方法) 在 java.lang.reflect.Method.invoke(Method.java:507) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) 在 dalvik.system.NativeStart.main( native 方法)

我在另一篇文章中读到我应该复制位图来避免这个问题,但无法弄清楚如何在我的代码中做到这一点。感谢您的帮助。第二个 Activity 的代码如下:

package com.example.app;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Base64;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.Toast;

public class ImageRotator extends Activity {
    private static final String TAG = "Rotator";
    private Uri file;
    private String suffix = "";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.picture);

        Bundle b = getIntent().getExtras();

        file = getIntent().getData();
        suffix = b.getString("suffix");

        Bitmap bm = this.getBitmap();


        ImageView box = (ImageView) findViewById(R.id.imageView1);
        box.setImageBitmap(bm);

        ImageButton v1 = (ImageButton) findViewById(R.id.rotateLeft);
        ImageButton v2 = (ImageButton) findViewById(R.id.rotateRight);
        ImageButton v3 = (ImageButton) findViewById(R.id.save);
        v1.setOnClickListener(new RotatorClass());
        v2.setOnClickListener(new RotatorClass());
        v3.setOnClickListener(new RotatorClass());
    }


    class RotatorClass implements ImageButton.OnClickListener
    {
        public void onClick(View v) {
            final int id = v.getId();

            int change = 0;

            switch(id) {
                case R.id.rotateLeft:
                    change = -90;
                    break;
                case R.id.rotateRight:
                    change = 90;
                    break;
                case R.id.save:
                    end(true);
                    return;
            }

            Log.d(TAG, "change: "+change);

            ImageRotator.this.rotate(change);
        }
    }


    @Override
    public void onBackPressed() {   
        final AlertDialog alertDialog = new AlertDialog.Builder(this).create();
        alertDialog.setTitle("Podane zdjęcie nie zostanie dodane. Kontynuować?");
        alertDialog.setButton("Tak", new DialogInterface.OnClickListener() {
              public void onClick(DialogInterface dialog, int which) {
                  end(false);
              }
        });

        alertDialog.setButton2("Nie", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                alertDialog.cancel();
            }
        });

        alertDialog.setCancelable(false);
        alertDialog.show();
    }

    public void rotate(int change) {
        // TODO Auto-generated method stub

        ImageView imageView = (ImageView) findViewById(R.id.imageView1);

        BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();
        BitmapFactory.Options options = new BitmapFactory.Options();
        Bitmap bm = drawable.getBitmap();
        Matrix matrix = new Matrix();
        matrix.postRotate(change);

        Bitmap bm2 = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
        bm = null;

        imageView.setImageBitmap(bm2);      
    }

    public String getRealPathFromURI(Uri contentUri) {
        String[] proj = { MediaStore.Images.Media.DATA };
        Cursor cursor = managedQuery(contentUri, proj, null, null, null);
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    }

    public void end(boolean save) {

        Intent in = new Intent();

        if(save == true) {

            File file2 = new File(getRealPathFromURI(file));

            try {
                FileOutputStream fos = new FileOutputStream(file2);
                ImageView imageView = (ImageView) findViewById(R.id.imageView1);
                BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();
                Bitmap bm = drawable.getBitmap();

                ByteArrayOutputStream baos = new ByteArrayOutputStream();  
                bm.compress(Bitmap.CompressFormat.JPEG, 30, baos);
                byte[] b = baos.toByteArray(); 

                String base = Base64.encodeToString(b, Base64.NO_WRAP);

                bm.compress(Bitmap.CompressFormat.PNG, 90, fos);
                fos.flush();
                fos.close();

                bm.recycle();
                bm = null;

                in.setData(file);

                in.putExtra("base", base);
                System.gc();
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        setResult(4,in);
        finish();
    }


    private Bitmap getBitmap() {

        Uri uri = this.file;
        InputStream in = null;

        ContentResolver mContentResolver = getContentResolver();

        try {
            final int IMAGE_MAX_SIZE = 300000;
            in = mContentResolver.openInputStream(uri);

            // Decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(in, null, o);
            in.close();

            int scale = 1;
            while ((o.outWidth * o.outHeight) * (1 / Math.pow(scale, 2)) > IMAGE_MAX_SIZE) {
                scale++;
            }
            Log.d(TAG, "scale = " + scale + ", orig-width: " + o.outWidth       + ", orig-height: " + o.outHeight);

            Bitmap b = null;
            in = mContentResolver.openInputStream(uri);
            if (scale > 1) {
                scale--;
                // scale to max possible inSampleSize that still yields an image
                // larger than target
                o = new BitmapFactory.Options();
                o.inSampleSize = scale;
                b = BitmapFactory.decodeStream(in, null, o);

                // resize to desired dimensions
                int height = b.getHeight();
                int width = b.getWidth();
                Log.d(TAG, "1th scale operation dimenions - width: " + width    + ", height: " + height);

                double y = Math.sqrt(IMAGE_MAX_SIZE
                        / (((double) width) / height));
                double x = (y / height) * width;

                Bitmap scaledBitmap = Bitmap.createScaledBitmap(b, (int) x,     (int) y, true);
                b.recycle();
                b = null;

                b = scaledBitmap;
            } else {
                b = BitmapFactory.decodeStream(in);
            }
            in.close();
            return b;
        } catch (IOException e) {
            Log.e(TAG, e.getMessage(),e);
            return null;
        }
    }
}

最佳答案

只需使用原始位图的复制功能。

位图 bm = drawable.getBitmap().copy(Bitmap.Config.ARGB_8888, false);

Config - 具有两个或三个可选值的枚举器,以支持像素表示。

bool 参数说明结果位图是否允许访问以编辑它的位。

关于android - "Can' t compress a recycled bitmap”单个设备异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11611667/

相关文章:

android - Android Studio始终加载支持库的旧版本

android - drawRect单元问题android

android - BadParcelableException:解码时出现 ClassNotFoundException

android - 如何创建 Bitmap 形式的 Drawable 对象

c# - control.DrawToBitmap() 未按预期工作

android - Visual Studio 不显示已安装的 Android api 级别

android - 是否可以将位图的点作为路径?

java - 从 BulkRequest 捕获特定的 Elasticsearch 异常

c# - 列表 <T> 中的 ArgumentOutOfRangeException

java - 在 BlackBerry ListField 中绘制边框