在 onActivityResult 中使用相机意图捕获的图片文件一段时间为空

Posted

技术标签:

【中文标题】在 onActivityResult 中使用相机意图捕获的图片文件一段时间为空【英文标题】:Picture file captured with camera intent empty for a while in onActivityResult 【发布时间】:2016-06-13 13:03:20 【问题描述】:

我遇到了一个非常奇怪的错误,试图通过意图拍照。 活动代码(稍微简化):

private void startCapture() throws IOException 
    // Create output file
    final File photoFile = makePhotoFile();
    _photoPath = photoFile.getAbsolutePath();

    Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    /* IMPORTANT NOTE TO READERS
     * As of android N (which went out shortly after I posted this question),
     * you cannot use Uri.fromFile this way anymore.
     * You should use a FileProvider. */
    cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));

    if (cameraIntent.resolveActivity(getPackageManager()) != null) 
        startActivityForResult(cameraIntent, REQUEST_CODE_IMAGE_CAPTURE);
    
    else 
        deleteCurrentPhoto();
    


private File makePhotoFile() throws IOException 
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(new Date());
    String imageFileName = "MyPhoto_" + timeStamp + "_";
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    return File.createTempFile(imageFileName, ".jpg", storageDir);


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) 
    super.onActivityResult(requestCode, resultCode, data);

    if(requestCode == REQUEST_CODE_IMAGE_CAPTURE) 
        if(resultCode == RESULT_OK) 
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            final byte[] buffer = new byte[2048];
            int read;
            byte[] photoBytes;
            try(FileInputStream fis = new FileInputStream(_photoPath)) 

                for(int i=0; i<10; i++)  // Always working after first iteration though
                    if( (read = fis.read(buffer)) <= 0) 
                        // Why does this get printed once ??
                        Log.w("my.package.my.app", "Empty for now...");
                    
                    else 
                        Log.w("my.package.my.app", "Working now !");
                        bos.write(buffer, 0, read);
                        break;
                    
                

                while((read = fis.read(buffer)) >= 0) 
                    bos.write(buffer, 0, read);
                

                photoBytes = bos.toByteArray();
             // Catch clauses removed for simplicity

            // Everything working OK after that (photoBytes decodes fine with the BitmapFactory)
        
    

还有日志输出:

03-01 16:32:34.139 23414-23414/my.package.my.app W/my.package.my.app: 暂时空... 03-01 16:32:34.139 23414-23414/my.package.my.app W/my.package.my.app:现在工作!

如你所见,在拍照后的onActivityResult中,第一次调用FileInputStream.read时文件为空……然后就可以正确读取了! 我认为当相机意图返回到调用活动时,文件已经被写入。有什么延迟吗?我也很惊讶地看到它总是在 for 循环中的一次迭代之后一直工作。

请注意,如果我在 onActivityResult 的开头放置一个断点,它会稍微延迟执行,并且一切正常(文件在第一次尝试时被正确读取)。

我正在使用 Android 6.0.1 下的库存 Nexus 6P 和库存相机应用。


重要编辑:对于 Android N,您应该使用 FileProvider 而不是 Uri.fromFile,就像我之前所做的那样。见this blog post 和these explanations from the Android team。

【问题讨论】:

File.createTempFile。不要已经创建该文件。您唯一需要的是文件名。一个文件路径。相机应用程序将创建该文件。所以重命名你的函数来创建新的文件名。 您应该记录read 的值。是0还是-1?或者将 ==0 和 不创建文件解决了问题,指南也创建了一个临时文件:developer.android.com/training/camera/photobasics.html(请参阅“保存全尺寸照片”部分。如果您有时间发布作为答案我可以接受(还有,知道为什么我会看到这种行为吗?),否则我会自己做。 当@greenapps 说不要创建 tempFile 时,您能发布一下您到底做了什么吗?我遇到了同样的问题,但不知道该怎么做 @MakrandGupta 只需将我的示例代码中的“File.create TempFile()”替换为“new File(storageDir, imageFileName + “.jpg”)。然后相机应用程序将为您创建文件。 【参考方案1】:

不要已经创建该文件。删除File.createTempFile()

您唯一需要的是文件名。一个文件路径。相机应用程序将自行创建文件。所以改变你的函数来创建新的文件名。例如。 new File(storageDir, imageFileName + ".jpg")

【讨论】:

您可能还想确保您创建的文件名是唯一的,方法 File.createTempFile() 可能用于强制您的文件名创建算法防冲突,如 Android documentation about taking pictures。跨度>

以上是关于在 onActivityResult 中使用相机意图捕获的图片文件一段时间为空的主要内容,如果未能解决你的问题,请参考以下文章

Android:使用相机意图时应用程序在 onActivityResult 上崩溃

在 onActivityResult 中使用相机意图捕获的图片文件一段时间为空

使用相机意图时未调用 OnActivityResult()?

在onActivityResult中使用相机意图捕获的图片文件空了一段时间

在棒棒糖中通过相机拍摄照片后,在 onActivityResult() 方法中获取空意图

从图库或相机返回后不调用 onActivityResult