从相机拍摄意图中保存图像到应用程序的私有存储位置

4

这里有很多关于如何在Android中创建一个外部存储文件,通过uri传递给ACTION_IMAGE_CAPTURE并将图像保存在那里的信息。

然而,我想在应用程序的私有存储(有时称为内部存储)中创建一个文件,并将该文件uri传递给ACTION_IMAGE_CAPTURE,但相机意图返回onActivityResult中的RESULT_CANCELED。

我该怎么办?

private void checkWhetherCameraIsAvailableAndTakeAPicture() {
    // Check wether this device is able to take pictures
    if (PhotoHandler.isIntentAvailable(a, MediaStore.ACTION_IMAGE_CAPTURE)) {
        System.gc();
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        File imageFile = null;

        try {
                if(a.application.user.isPublishImagesToGallery()){
                imageFile = a.application.photoHandler.createImageFileOnExternalStorage();
            } else {
                imageFile = a.application.photoHandler.createImageFileOnInternalStorage();
            }

            imagePath = imageFile.getAbsolutePath();
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(imageFile));
        } catch (IOException e) {
            e.printStackTrace();
            imageFile = null;
            imagePath = null;
        }
        startActivityForResult(takePictureIntent, Preferences.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA);
    } else { // Notify the user that their device is unable to take photos
        a.application.toastMaker.toastLong(ErrorMessages.DEVICE_UNABLE_TO_TAKE_PHOTOS);
    }
} // End of checkWhetherCameraIsAvailableAndTakeAPicture

public File createImageFileOnInternalStorage() throws IOException {
        return createTempFileOnGivenLocation();
    }

    private String imageFilename() {
        return filenamePrefix + Calendar.getInstance().getTimeInMillis();
    }

    private File createTempFileOnGivenLocation() throws IOException {
        File imageFile = File.createTempFile(imageFilename(), filenameSuffix, context.getFilesDir());
        setImagePathTemporary(imageFile.toString());

        return imageFile;
    }


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

    if (requestCode == Preferences.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA) {
        if (resultCode != Activity.RESULT_CANCELED) {
            handlePhotoTakenWithCamera();
        } else {
            // ONACTIVITYRESULT Returns Here!
            new File(imagePath).delete())
        }
    } else if (requestCode == Preferences.REQUEST_CODE_PICK_IMAGES_FROM_GALLERY) {
        if (resultCode != Activity.RESULT_CANCELED) {
            handlePhotosPickedFromGallery(data);
        }
    }
} // End of onActivityResult
2个回答

1
正如此答案中所述,相机应用程序无法直接写入您的应用程序内部存储器。
但是,您可以编写内容提供程序,该提供程序将能够作为流从相机应用程序消耗数据并自行保存。
以下是使相机应用程序知道在何处放置文件的方法。
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
Uri uri = Uri.withAppendedPath(CONTENT_URI_OF_YOUR_CONTENT_PROVIDER, "id_of_your_image");
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(takePictureIntent, CAMERA_REQUEST);  

如何构建实际的内容提供者,我认为超出了这个问题的范围。请阅读上面链接的文档并在SO上搜索相关问题。一个提示是,你需要实现insert方法来完成它。可能会像这样。
public Uri insert(Uri uri, ContentValues values) {
    String name = uri.getPath();
    File file = new File(name);     
    OutputStream stream = new FileOutputStream(file);
    byte[] data = (byte[]) values.get(KEY_FILE_CONTENT);
    try {
        stream.write(data);
        stream.flush();
        stream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return uri;
}

但由于内容提供商的复杂性,上述代码可能无法直接使用。


@J.K. 我已经编辑了问题并提供了更多信息。顺便说一句,我认为我的方法比之前的答案更好。你不需要自己复制文件,相机会通过内容提供程序直接将其写入内部存储器。(这也意味着图像可能永远不会存储在公共目录中 - 安全性:) - 但这实际上取决于相机应用本身) - simekadam
非常感谢。如果可以的话,我会尝试这个。 - Kaloyan Roussev

1
内部存储对于每个应用程序是私有的。相机应用无法访问您应用程序的内部存储。获取内部存储中的图像的最佳方法是:
1)在应用程序内部使用自己的相机拍摄图片
或者
2)使用相机意图来捕获照片,该照片将保存到外部存储中。在 onActivityResult 中,将图像复制到您应用程序的内部存储并从外部存储中删除。可以在此答案中找到复制文件的代码。 https://dev59.com/6W445IYBdhLWcg3wnrrM#4770586

@J.K. 很好。祝你好运。 - Ahmad Nawaz
1
复制文件的代码可以在这个答案中找到。https://dev59.com/6W445IYBdhLWcg3wnrrM#4770586 - Ahmad Nawaz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接