【问题标题】:How to get uri of captured photo?如何获取拍摄照片的uri?
【发布时间】:2017-11-23 05:39:03
【问题描述】:

我想实现什么? 我想获取捕获图像的 URI 并将其保存在 Firebase 上。 我尝试了什么? 首先我需要打开相机。下面我是如何做到的:

 Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    if (cameraIntent.resolveActivity(getActivity().getPackageManager()) != null)
        startActivityForResult(cameraIntent, CAMERA_REQUEST_CODE);

捕获图像后,我需要获取图像的 URI。下面我是如何做到的:

if (resultCode == Activity.RESULT_OK) {
        if (requestCode == CAMERA_REQUEST_CODE) {
            if (data != null) {
                if (data.getData() != null) {
                   Uri capturedImageUri = data.getData(); 
                } else {
                    Toast.makeText(getContext(), getString(R.string.coudldnt_get_photo), Toast.LENGTH_SHORT).show();
                }
            } else {
                Toast.makeText(getContext(), getString(R.string.coudldnt_get_photo), Toast.LENGTH_SHORT).show();
            }

所以一切都很好。但仅在某些设备上。我想它只适用于超过 21 个设备的 API 级别。在其他设备中,getData() 返回 null。

那么,接下来我做了什么? 我发现我可以通过以下代码获取图像的位图:

Bitmap bitmap = (Bitmap)data.getExtras().get("data") ; 

所以,我有一张图像的位图。我需要获取这张图片的 URI。下面我是如何做到的:

public Uri getImageUri(Context inContext, Bitmap inImage) {
  String path = 
  Images.Media.insertImage(inContext.getContentResolver(), inImage, 
  "Title", null);
  return Uri.parse(path);
 } 

上面的代码返回了 URI,但是图片质量很差。

所以,我一直在寻找解决方案。并发现正确的方法是在我启动CameraActivity时创建文件并保存该文件的uri。而onActivityResult 我试图得到那个uri。下面我是如何做到的:

Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    if (cameraIntent.resolveActivity(getActivity().getPackageManager()) != null) {
        File photoFile = null;
        try {
            photoFile = createImageFile();
        } catch (IOException ex) {

        }
        if (photoFile != null) {
            Uri photoUri = FileProvider.getUriForFile(getContext(), "i_dont_know_what_to_write_here", photoFile);
            cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
            startActivityForResult(cameraIntent, CAMERA_REQUEST_CODE);
        }

    }

我的onActivityResult变成了:

    if (resultCode == Activity.RESULT_OK) {
    if (requestCode == CAMERA_REQUEST_CODE) {
        if (data != null) {
 Uri capturedPhotoUri = 
 data.getParcelableExtra(MediaStore.EXTRA_OUTPUT);
   } else {
   Toast.makeText(getContext(), 
   getString(R.string.coudldnt_get_photo), Toast.LENGTH_SHORT).show();
            }

上述概念需要在清单上添加一些标签:

 <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="i_dont_know_what_to_write_here"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/my_paths" />
        </provider>

我的 xml 文件是:

<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-files-path name="images"/>
</paths>

上述方法无效,因为onActivityReuslt 上的data 为空。

那么,我需要做什么才能实现我的目标?

【问题讨论】:

  • @akhilesh0707 谢谢,但那里的答案是关于如何从 uri 获取文件路径。我的问题是获取uri。我该如何使用它?
  • So, I have a bitmap of the image. And I needed to get the URI of this image.。是的,你有一个位图。你只有一个位图。位图没有 uri。所以不要要求该位图/图像的 uri。但是,您可以做的是将该位图保存到文件中,然后从文件中获取 uri。或者将位图保存到媒体存储中,然后从存储中获取 uri。但是位图仍然没有 uri。

标签: android android-camera uri android-fileprovider


【解决方案1】:

按照以下步骤操作。

步骤 - 1:在 res/xml 文件夹中创建 provider_paths.xml 并在其中写入以下代码。

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path
        name="external_files"
        path="." />
</paths>

第 2 步:在清单中声明提供者,如下所示。

       <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>

如果您在以下位置遇到错误:android:name="android.support.v4.content.FileProvider" 使用:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.provider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths" />
</provider>

第 3 步:编写您的相机意图,如下所示。

    Intent m_intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    File file = new File(Environment.getExternalStorageDirectory(), "MyPhoto.jpg");
    Uri uri = FileProvider.getUriForFile(this, this.getApplicationContext().getPackageName() + ".provider", file);
    m_intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, uri);
    startActivityForResult(m_intent, REQUEST_CAMERA_IMAGE);

Step - 4 : 在 onActivityResult 中处理相机结果如下。

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {

        //TODO... onCamera Picker Result
        case REQUEST_CAMERA_IMAGE:
            if (resultCode == RESULT_OK) {

              //File object of camera image
                File file = new File(Environment.getExternalStorageDirectory(), "MyPhoto.jpg");

              //Uri of camera image
                Uri uri = FileProvider.getUriForFile(this, this.getApplicationContext().getPackageName() + ".provider", file);

            }
            break;
    }
}

【讨论】:

  • 您的解决方案需要更多代码。我还没试过。但是想问一下,您的解决方案与以下答案相比有什么优势?
  • 我使用了 FileProvider 的概念,所以这段代码在所有的 android 版本(从 KitKat 到 Oreo)都可以正常工作。此外,如果您想直接访问文件,这是谷歌推荐使用 FileProvider 的。看看这个链接developer.android.com/reference/android/support/v4/content/…
  • 非常干净的解决方案!我成功获得了 URI,之后我需要在 recyclerview 上显示它。但毕加索无法通过其 URI 加载该图像。可能是什么问题?
  • 好吧,我已经使用 URL 使用 glide 加载图像,它工作正常。但是,如果您无法使用 URI 加载图像,那么您也可以尝试使用 file.getAbsolutePath() 来获取捕获的图像路径。
  • 我会接受你的回答,但你能帮我解决这些问题吗: 1) 正如我所注意到的,照片保存在设备存储中。但它没有文件夹,它被放在文件夹之间。如何为照片创建文件夹? 2) 我需要向WRITE_EXTERNAL_STORAGE 询问您的方法吗? 3)file.getAbsolutePath() 返回以下:/storage/emulated/0/MyPhoto.jpg,当getUriForFile() 返回:content://app_package_name.provider/external_files/MyPhoto.jpg 为什么它们不同? 4)Picasso 和 Glide 都无法通过 uri 在适配器中转换为字符串来加载照片。如何解决?
【解决方案2】:

调用相机意图时

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);


 File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_PICTURES), "IMG_FOLDER");

        try {
            if (!mediaStorageDir.exists()) {
                if (!mediaStorageDir.mkdirs()) {
                    return null;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }


        imageURI = Uri.fromFile(new File(mediaStorageDir.getPath() + File.separator +
                "profile_img.jpg"));
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageURI);

        startActivityForResult(intent, Utils.CAMERA_REQUEST);

onActivityResult 内部

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        try {
            if (resultCode == RESULT_OK) {
                if (requestCode == Utils.CAMERA_REQUEST) {
                    if (imageURI != null) {             // use the same uri, that you initialized while calling camera intent
                     // do whatever you want to do with this Uri
                 }
                }
            }
         } catch(Exception E) {}  
  }

对于牛轧糖,您需要在启动/启动器活动中添加以下代码

if (Build.VERSION.SDK_INT >= 24) {
        try {
            Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure");
            m.invoke(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

这适用于所有版本。我也测试过了。

【讨论】:

  • 您的解决方案很好,但它会覆盖之前捕获的图像。那么,如何避免呢?
  • 您可以使用arrayList来添加新图像。
  • android.os.FileUriExposedException: file:///storage/emulated/0/Pictures/Qamqor/qamqor_20171124_120531.jpg 通过 ClipData.Item.getUri() 暴露在应用程序之外 不幸的是,当我遇到上述错误时cameraActivity 开始
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-31
相关资源
最近更新 更多