从相机返回时,什么会导致一个Android活动,无限重启本身?重启、相机、Android

2023-09-12 05:00:08 作者:圈子不同别硬触.

我有一个奇怪的错误,在我的应用程序,导致活动以重新启动本身在一个无限循环,当我从一个摄像头应用程序返回,拍摄照片后。

用户界面流程是这样的:

主要活动 - > 在接受摄影活动 - >中的onCreate()打开相机startActivityForResult() 在相机屏幕 - >拍照(或取消) - >返回接受照片 在接受照片画面完全创建并立即停止并重新创建一个无限循环

怪异的部分是,它只是发生了一些摄像头。在我的Nexus S运行杰利贝恩,股票摄像机行为正确,而相机变焦FX导致此错误。在我的爱可视G9平板电脑运行ICS,无论是股票摄像头和变焦FX导致错误。

我检查了一步的code一步,我无法找到的重新启动电话的来源。当我停在第二个(和后续)调试器的onCreate()调用,调用堆栈有一个ActivityThread.handleRelaunchActivity()调用。它的意图并没有太多的信息:该操作为空,则类是AcceptPhoto。该mFlags有603979776价值,我不知道如何转化为实际的意图的标志。

怪胎还不止于此,虽然。在我的平板电脑,我第一次拍照时,该应用程序是好的。如果我试图拍摄一张照片,画面都疯了。而不是采取秒的画面如果,我返回到previous屏幕,这一切都很正常,直到我打开一个新的活动。它不会从哪儿无所谓,如果我一路回到根系活力,并开始一个新的活动,它开始闪烁。

我会尝试发布一些code,但我怀疑这个错误不是由我的code引起的,但我引发一些底层的Andr​​oid code。我希望的是,也许有人可以点我在正确的方向上找到一个方法来解决这个问题。什么都可以有帮助,所以我感谢你的任何想法!

用于打开相机时,code(称为AcceptPhoto.onCreate(),使用工具类):

 私人无效openCamera(上下文的背景下){
    意图pictureIntent =新的意图(MediaStore.ACTION_IM​​AGE_CAPTURE);
    文件临时文件= getTempFile(上下文);
    尝试 {
        如果(临时文件!= NULL){

            pictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(临​​时文件));

            ((活动)范围内).startActivityForResult(pictureIntent,GET_ITEM_PHOTO);
        } 其他 {
            Toast.makeText(背景下,无法创建临时文件,Toast.LENGTH_SHORT).show();
        }
    }赶上(例外五){
        Toast.makeText(背景下,错误打开摄像机+ e.getMessage(),Toast.LENGTH_LONG).show();
        e.printStackTrace();
    }
}
 

用于显示图像,称为AcceptPhoto.onActivityResult()的code:

 私人无效displayPhoto(){
    如果(cameraUtils == NULL){
        cameraUtils =新CameraUtil();
    }
    previewImageView.setImageDrawable(空);
    文件临时文件= cameraUtils.getTempFile(本);

    INT旋转= 0;
    尝试 {
        ExifInterface EXIF​​ =新ExifInterface(tempFile.getPath());
        字符串的方向= exif.getAttribute(ExifInterface.TAG_ORIENTATION);
        Log.i(春,照片显示方向+方向);
        旋转= getBitmapRotation(Integer.valueOf(取向));
        Log.i(春,形象需要通过旋转+(旋转)+度);
    }赶上(IOException异常E1){
        e1.printStackTrace();
    }
    尝试 {
        previewBitmap = BitmapEn coderUtil.load prescaledBitmap(临时文件);
        如果(旋转!= 0){

            矩阵rotationMatrix =新的Matrix();
            rotationMatrix.postRotate(旋转);

            INT W = previewBitmap.getWidth();
            INT H = previewBitmap.getHeight();

            位图rotatedBitmap = Bitmap.createBitmap(previewBitmap,0,0,W,H,rotationMatrix,假);

            previewBitmap = rotatedBitmap;
        }
        previewImageView.setImageBitmap(previewBitmap);
    }赶上(FileNotFoundException异常E){
        // TODO自动生成的catch块
        e.printStackTrace();
    }赶上(IOException异常E){
        // TODO自动生成的catch块
        e.printStackTrace();
    }
}
 
三星EK GC100 Galaxy相机图赏 搭载Android 4.1系统

在工具类用于创建/检索相机进行保存照片文件的方法:

 公开文件getTempFile(上下文的背景下){

    串externalStorageStateString = Environment.getExternalStorageState();
    文件cacheDirectory;
    //尝试保存在外部存储
    如果(externalStorageStateString.equals(Environment.MEDIA_MOUNTED)){
        cacheDirectory = context.getExternalCacheDir();
    } 其他 {
        //保存在内部存储
        cacheDirectory = context.getCacheDir();
    }
    文件tempSnapshotFile =新的文件(cacheDirectory,MissionOtherActivity.ITEM_SNAPSHOT_PATH);

    //请确保该文件存在,对于相机的错误可能的修复
    尝试 {
        如果(tempSnapshotFile.exists()== FALSE){
            tempSnapshotFile.getParentFile()mkdirs()。
            tempSnapshotFile.createNewFile();
        }

    }赶上(IOException异常E){
        Log.e(春,无法创建文件,E);
    }
    返回tempSnapshotFile;
}
 

解决方案

经过大量的调查,它出现在调用重新启动是从onConfigurationChanged到来。我还没有想通了,为什么,但至少我知道的避免这些东西。

这解释了为什么一些相机触发此问题,并没有其他人:某些相机使用相同的配置,我的应用程序,其他人不是

编辑:我发现,我在扩展应用类有一个bug其他调查之后。在onConfigurationChanged方法,我正在改变,迫使某一区域的配置。这是引发了新onConfigurationChanged()调用,这导致无限循环和随后屏幕创建/销毁顺序。我不知道为什么我已经把那个code在onConfigurationChanged()方法,但我猜你有才能学会受苦。)

I have a weird bug in my application that causes an activity to relaunch itself in an infinite loop when I'm returning from a camera application, after taking a picture.

The UI flow is like this:

Main Activity -> Accept Photo activity -> in onCreate() open camera with startActivityForResult() Camera screen -> take picture (or cancel) -> return to Accept Photo The Accept Photo screen is created completely and immediately stopped and recreated in an infinite loop

The weird part is that it only happens for some cameras. On my Nexus S running Jellybean, the stock camera behaves correctly, while Camera Zoom FX causes this bug. On my Archos G9 tablet running ICS, both the stock camera and Zoom FX cause the bug.

I've checked the code step by step and I can't find the source of the relaunch call. When I'm stopping the debugger in the second (and subsequent) onCreate() call, in the call stack there is an ActivityThread.handleRelaunchActivity() call. It's Intent doesn't have much info: the action is null, the class is AcceptPhoto. The mFlags has the 603979776 value, which I don't know how to translate into the actual intent flags.

The weirdness doesn't stop here, though. On my tablet, the first time I take the picture, the application is fine. If I try to take a second picture, the screen goes crazy. If, instead of taking the seconds picture, I return to a previous screen, it's all fine until I open a new activity. It doesn't matter from where, if I return all the way to the root activity and start a new activity, it starts flickering.

I'll try to post some code, but I suspect the bug is not caused by my code, but I'm triggering something in the underlying Android code. What I hope for is maybe someone can point me in the correct direction to find a way to work around this bug. Anything can be helpful, so I thank you for any idea!

The code used to open the camera (called in AcceptPhoto.onCreate(), using an utility class):

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();
    }
}

The code used to display the picture, called in 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();
    }
}

Method used in the utility class to create/retrieve the file where the camera saves the photo:

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;
}

解决方案

After much investigation, it appears the call to relaunch is coming from onConfigurationChanged. I still haven't figured out why, but at least I know what to avoid.

It explains why some cameras triggered this bug and others not: some cameras used the same configuration as my application, others not.

EDIT: I've discovered after other investigations that I had a bug in my extended Application class. In the onConfigurationChanged method, I was changing the configuration by forcing a certain locale. This was triggering a new onConfigurationChanged() call, which caused an infinite loop and the subsequent screen create/destroy sequence. I have no idea why I've put that code in the onConfigurationChanged() method, but I guess you have to suffer in order to learn :)