11

写真を撮った後、カメラ アプリケーションから戻ると、アプリケーションに奇妙なバグがあり、アクティビティが無限ループで再起動します。

UI フローは次のようになります。

  1. 主な活動 ->
  2. 写真アクティビティを受け入れる -> onCreate() で、startActivityForResult() でカメラを開きます
  3. カメラ画面 -> 写真を撮る (またはキャンセル) -> 写真の承認に戻る
  4. Accept Photo 画面が完全に作成され、すぐに停止し、無限ループで再作成されます。

奇妙な部分は、一部のカメラでのみ発生することです。Jellybean を実行している Nexus S では、ストック カメラは正しく動作しますが、Camera Zoom FX はこのバグを引き起こします。ICS を実行している私の Archos G9 タブレットでは、ストック カメラと Zoom FX の両方がバグを引き起こします。

コードを段階的に確認しましたが、再起動呼び出しのソースが見つかりません。2 回目 (およびそれ以降) の onCreate() 呼び出しでデバッガーを停止すると、コール スタックに ActivityThread.handleRelaunchActivity() 呼び出しがあります。Intent にはあまり情報がありません。アクションは null、クラスは AcceptPhoto です。mFlags には 603979776 の値があり、実際のインテント フラグに変換する方法がわかりません。

しかし、奇妙さはここで止まりません。私のタブレットでは、初めて写真を撮るとき、アプリケーションは問題ありません。2 枚目の写真を撮ろうとすると、画面がおかしくなります。秒の写真を撮る代わりに前の画面に戻った場合、新しいアクティビティを開くまでは問題ありません。どこからでも問題ありません。ルート アクティビティに戻って新しいアクティビティを開始すると、ちらつき始めます。

いくつかのコードを投稿しようとしますが、バグは私のコードが原因ではないと思われますが、基になる 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 に答える