【问题标题】:Camera Crashes on orientation相机在方向上崩溃
【发布时间】:2014-12-22 19:05:04
【问题描述】:

我正在使用来自https://github.com/jdamcd/android-crop 的裁剪图像库从图库和相机中获取图像。如果我在从相机获取图像后不改变方向,它在相机上工作正常。但是,当我像在裁剪之前一样单击图像后更改方向时,应用程序会崩溃。很少有博客被告知使用android:configChanges="orientation|keyboardHidden|screenSize",但它不起作用。即使我已将 Manifest 文件中的方向锁定在我调用裁剪方法的活动上。我的代码和错误堆栈如下:

package eu.janmuller.android.simplecropimage.example;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import eu.janmuller.android.simplecropimage.CropImage;

public class MainActivity extends Activity {

    public static final String TAG = "MainActivity";

    public static final String TEMP_PHOTO_FILE_NAME = "temp_photo.jpg";
    private File      mFileTemp;
    public static final int REQUEST_CODE_GALLERY      = 0x1;
    public static final int REQUEST_CODE_TAKE_PICTURE = 0x2;
    public static final int REQUEST_CODE_CROP_IMAGE   = 0x3;

    private ImageView mImageView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);    //To change body of overridden methods use File | Settings | File Templates.
        setContentView(R.layout.main);

        findViewById(R.id.gallery).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                openGallery();
            }
        });

        findViewById(R.id.take_picture).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                takePicture();
            }
        });

        mImageView = (ImageView) findViewById(R.id.image);

        String state = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED.equals(state)) {
            mFileTemp = new File(Environment.getExternalStorageDirectory(), TEMP_PHOTO_FILE_NAME);
        }
        else {
            mFileTemp = new File(getFilesDir(), TEMP_PHOTO_FILE_NAME);
        }

    }

    private void takePicture() {

        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

        try {
            Uri mImageCaptureUri = null;
            String state = Environment.getExternalStorageState();
            if (Environment.MEDIA_MOUNTED.equals(state)) {
                mImageCaptureUri = Uri.fromFile(mFileTemp);
            }
            else {
                /*
                 * The solution is taken from here: http://stackoverflow.com/questions/10042695/how-to-get-camera-result-as-a-uri-in-data-folder
                 */
                mImageCaptureUri = InternalStorageContentProvider.CONTENT_URI;
            }   
            intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, mImageCaptureUri);
            intent.putExtra("return-data", true);
            startActivityForResult(intent, REQUEST_CODE_TAKE_PICTURE);
        } catch (ActivityNotFoundException e) {

            Log.d(TAG, "cannot take picture", e);
        }
    }

    private void openGallery() {

        Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
        photoPickerIntent.setType("image/*");
        startActivityForResult(photoPickerIntent, REQUEST_CODE_GALLERY);
    }

    private void startCropImage() {

        Intent intent = new Intent(this, CropImage.class);
        intent.putExtra(CropImage.IMAGE_PATH, mFileTemp.getPath());
        intent.putExtra(CropImage.SCALE, true);
        intent.putExtra(CropImage.ASPECT_X, 3);
        intent.putExtra(CropImage.ASPECT_Y, 3);

        startActivityForResult(intent, REQUEST_CODE_CROP_IMAGE);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        if (resultCode != RESULT_OK) {

            return;
        }

        Bitmap bitmap;

        switch (requestCode) {

            case REQUEST_CODE_GALLERY:

                try {

                    InputStream inputStream = getContentResolver().openInputStream(data.getData());
                    FileOutputStream fileOutputStream = new FileOutputStream(mFileTemp);
                    copyStream(inputStream, fileOutputStream);
                    fileOutputStream.close();
                    inputStream.close();

                    startCropImage();

                } catch (Exception e) {

                    Log.e(TAG, "Error while creating temp file", e);
                }

                break;
            case REQUEST_CODE_TAKE_PICTURE:

                startCropImage();
                break;
            case REQUEST_CODE_CROP_IMAGE:

                String path = data.getStringExtra(CropImage.IMAGE_PATH);
                if (path == null) {

                    return;
                }

                bitmap = BitmapFactory.decodeFile(mFileTemp.getPath());
                mImageView.setImageBitmap(bitmap);
                break;
        }
        super.onActivityResult(requestCode, resultCode, data);
    }


    public static void copyStream(InputStream input, OutputStream output)
            throws IOException {

        byte[] buffer = new byte[1024];
        int bytesRead;
        while ((bytesRead = input.read(buffer)) != -1) {
            output.write(buffer, 0, bytesRead);
        }
    }

}

错误堆栈如下:

12-22 23:11:03.372: E/AndroidRuntime(3617): java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@41bd8728
12-22 23:11:03.372: E/AndroidRuntime(3617):     at android.graphics.Canvas.throwIfRecycled(Canvas.java:1026)
12-22 23:11:03.372: E/AndroidRuntime(3617):     at android.graphics.Canvas.drawBitmap(Canvas.java:1096)
12-22 23:11:03.372: E/AndroidRuntime(3617):     at android.graphics.Bitmap.createBitmap(Bitmap.java:625)
12-22 23:11:03.372: E/AndroidRuntime(3617):     at eu.janmuller.android.simplecropimage.CropImage$1.prepareBitmap(CropImage.java:572)
12-22 23:11:03.372: E/AndroidRuntime(3617):     at eu.janmuller.android.simplecropimage.CropImage$1.run(CropImage.java:578)
12-22 23:11:03.372: E/AndroidRuntime(3617):     at eu.janmuller.android.simplecropimage.CropImage$6.run(CropImage.java:285)
12-22 23:11:03.372: E/AndroidRuntime(3617):     at eu.janmuller.android.simplecropimage.Util$BackgroundJob.run(Util.java:175)
12-22 23:11:03.372: E/AndroidRuntime(3617):     at java.lang.Thread.run(Thread.java:838)

提前致谢!

【问题讨论】:

  • 没有堆栈跟踪和代码,我们将无法提供太多帮助。尝试同时发布它们。
  • 很抱歉给您带来不便。我要把它贴在这里。
  • @GabeSechan 请现在检查我编辑的代码。我也在这里粘贴了我的错误堆栈。

标签: android image camera orientation config


【解决方案1】:

您正在尝试绘制已被回收的位图。看起来它的意图是你用来裁剪图像的意图 - 它重写已经破坏的位图。我的猜测是库有一个错误,它在其 onStop 中回收位图以提高效率,但没有意识到位图仍然可以被库中的 AsyncTask 或线程使用,并且他们没有检查它是否先回收。您可能可以通过添加一些 isRecycled() 检查来修复他的库,但我猜还有其他竞争条件。您可以通过将 configChanges 行添加到他的库的活动来修复它,因此它们不会在轮换时进行活动重新创建。

但问题在于他的库,而不是你的代码。

【讨论】:

  • 你能推荐任何用于图像裁剪的库项目吗?
  • 并非如此。我以前裁剪过图像,但我自己滚动而不是使用库,而且我对代码没有合法权利。我敢肯定那里有好的,我就是不能推荐。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-18
  • 2018-04-23
  • 2018-10-12
  • 2021-05-27
  • 1970-01-01
相关资源
最近更新 更多