什么可能导致Android活动从相机返回时无限重新启动自己?

Cor*_*ălu 11 camera android restart infinite-loop android-activity

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

UI流程如下:

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

奇怪的是,它只发生在一些相机上.在运行Jellybean的Nexus S上,相机的行为正常,而Camera Zoom FX则会导致此错误.在运行ICS的Archos G9平板电脑上,相机和Zoom FX都会导致错误.

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

不过,这种古怪并不止于此.在我的平板电脑上,我第一次拍照时,应用程序很好.如果我尝试拍第二张照片,屏幕会变得疯狂.如果我没有拍摄秒图片,而是返回上一个屏幕,那么在我打开新活动之前一切正常.无论从哪里开始,如果我一直返回到根活动并开始一个新的活动,它就会开始闪烁.

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

用于打开相机的代码(使用实用程序类在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();
    }
}
Run Code Online (Sandbox Code Playgroud)

用于显示图片的代码,在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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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;
}
Run Code Online (Sandbox Code Playgroud)

Cor*_*ălu 19

经过大量调查后,似乎重新启动的呼叫来自onConfigurationChanged.我还是没弄明白为什么,但至少我知道该避免什么.

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

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

  • 我也在Application.onConfigurationChanged()中强制使用语言环境,并且在无限调用方法时也存在问题.在我的所有活动中添加`android:configChanges ="locale"`为我解决了这个问题. (3认同)
  • 是的,你是对的.我正在使用强制语言环境.出于某种原因,我正在更新Application.onConfigurationChanged()中的配置,这导致了无限循环. (2认同)
  • @AlvaroSantisteban在app的第一个活动的onCreate()中.我存储选定的语言和一个标志,以指示我是否应该强制使用语言环境.如果是这样,我在onCreate()中做的第一件事就是设置语言环境并重新启动活动. (2认同)