11

我的应用程序中有一个奇怪的错误,当我在拍照后从相机应用程序返回时,导致活动在无限循环中重新启动。

UI流程是这样的:

  1. 主要活动->
  2. 接受照片活动 -> 在 onCreate() 中使用 startActivityForResult() 打开相机
  3. 相机屏幕->拍照(或取消)->返回接受照片
  4. 接受照片屏幕完全创建并立即停止并在无限循环中重新创建

奇怪的是,它只发生在某些相机上。在我运行 Jellybean 的 Nexus S 上,普通相机运行正常,而 Camera Zoom FX 导致了这个错误。在我运行 ICS 的 Archos G9 平板电脑上,备用相机和 Zoom FX 都会导致该错误。

我一步步检查了代码,找不到重新启动调用的来源。当我在第二个(以及后续的)onCreate() 调用中停止调试器时,调用堆栈中有一个 ActivityThread.handleRelaunchActivity() 调用。它的 Intent 没有太多信息:action 为 null,类为 AcceptPhoto。mFlags 具有 603979776 值,我不知道如何将其转换为实际的意图标志。

不过,怪异并不止于此。在我的平板电脑上,我第一次拍照时,应用程序很好。如果我尝试拍摄第二张照片,屏幕会发疯。如果我没有拍摄第二张照片,而是返回到前一个屏幕,那么在我打开一个新活动之前一切都很好。从哪里开始并不重要,如果我一直返回到根活动并开始一个新活动,它就会开始闪烁。

我会尝试发布一些代码,但我怀疑这个错误不是由我的代码引起的,而是我在底层 Android 代码中触发了一些东西。我希望有人能指出我正确的方向,以找到解决此错误的方法。任何事情都会有所帮助,所以我感谢您的任何想法!

用于打开相机的代码(在 AcceptPhoto.onCreate() 中调用,使用实用程序类):

private void openCamera(Context context) {
    Intent pictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    File tempFile = getTempFile(context);
    try {
        if (tempFile != null) {

            pictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile));

            ((Activity) context).startActivityForResult(pictureIntent, GET_ITEM_PHOTO);
        } else {
            Toast.makeText(context, "Could not create temp file", Toast.LENGTH_SHORT).show();
        }
    } catch (Exception e) {
        Toast.makeText(context, "Error opening camera " + e.getMessage(), Toast.LENGTH_LONG).show();
        e.printStackTrace();
    }
}

用于显示图片的代码,在 AcceptPhoto.onActivityResult() 中调用:

private void displayPhoto() {
    if (cameraUtils == null) {
        cameraUtils = new CameraUtil();
    }
    previewImageView.setImageDrawable(null);
    File tempFile = cameraUtils.getTempFile(this);

    int rotation = 0;
    try {
        ExifInterface exif = new ExifInterface(tempFile.getPath());
        String orientation = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
        Log.i("SPRING", "Photo orientation " + orientation);
        rotation = getBitmapRotation(Integer.valueOf(orientation));
        Log.i("SPRING", "The image needs to be rotated by " + (rotation) + " degrees");
    } catch (IOException e1) {
        e1.printStackTrace();
    }
    try {
        previewBitmap = BitmapEncoderUtil.loadPrescaledBitmap(tempFile);
        if (rotation != 0) {

            Matrix rotationMatrix = new Matrix();
            rotationMatrix.postRotate(rotation);

            int w = previewBitmap.getWidth();
            int h = previewBitmap.getHeight();

            Bitmap rotatedBitmap = Bitmap.createBitmap(previewBitmap, 0, 0, w, h, rotationMatrix, false);

            previewBitmap = rotatedBitmap;
        }
        previewImageView.setImageBitmap(previewBitmap);
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

实用程序类中用于创建/检索相机保存照片的文件的方法:

public File getTempFile(Context context) {

    String externalStorageStateString = Environment.getExternalStorageState();
    File cacheDirectory;
    // try to save in external storage
    if (externalStorageStateString.equals(Environment.MEDIA_MOUNTED)) {
        cacheDirectory = context.getExternalCacheDir();
    } else {
        // save in internal storage
        cacheDirectory = context.getCacheDir();
    }
    File tempSnapshotFile = new File(cacheDirectory, MissionOtherActivity.ITEM_SNAPSHOT_PATH);

    // make sure the file exists, possible fix for the camera bug
    try {
        if (tempSnapshotFile.exists() == false) {
            tempSnapshotFile.getParentFile().mkdirs();
            tempSnapshotFile.createNewFile();
        }

    } catch (IOException e) {
        Log.e("SPRING", "Could not create file.", e);
    }
    return tempSnapshotFile;
}
4

1 回答 1

19

经过大量调查,似乎重新启动的调用来自 onConfigurationChanged。我仍然没有弄清楚为什么,但至少我知道要避免什么。

它解释了为什么有些摄像头会触发此错误而有些则不会:有些摄像头使用与我的应用程序相同的配置,而其他摄像头则没有。

编辑:经过其他调查,我发现我的扩展应用程序类中有一个错误。在 onConfigurationChanged 方法中,我通过强制某个区域设置来更改配置。这触发了新的 onConfigurationChanged() 调用,这导致了无限循环和随后的屏幕创建/销毁序列。我不知道为什么我把代码放在 onConfigurationChanged() 方法中,但我想你必须受苦才能学习:)

于 2012-10-04T07:25:54.537 回答