Android 7.0使用FileProvider获取相机拍照的图片路径

时间:2022-06-01 18:20:23

这里主要是基于Android 7.0,Nougat 实现一个获取相机拍照的图片后,使用FileProvider把图片转换为实际的路径。

首先需要在AndroidManifest.xml声明调用相机的权限

<manifest>
...
      <uses-feature android:name="android.hardware.camera"
                  android:required="true" />
...
</manifest>

接着在Activity里实现打开相机拍照

private static final int REQUEST_CAPTURE_IMAGE = 100;

private void openCameraIntent() {
    Intent pictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if(pictureIntent.resolveActivity(getPackageManager()) != null) { 
           startActivityForResult(pictureIntent,REQUEST_CAPTURE_IMAGE);
    }
}

在onActivityResult处理拍照捕获图片的结果

@Override
protected void onActivityResult(int requestCode, int resultCode,
                                              Intent data) {
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
        if (data != null && data.getExtras() != null) {
        Bitmap imageBitmap = (Bitmap) data.getExtras().get("data");
        imageView.setImageBitmap(imageBitmap);
        }
    }
}

这里在ImageView里直接显示Bitmap。如果需要上传图片到服务器,需要把图片保存为临时文件。

创建文件需要声明对外部存储的写权限,在AndroidManifest.xml声明如下:

<manifest>
     ...
<uses-permission
       android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
</manifest>

创建用于保存图片的临时文件createImageFile:

String imageFilePath;
private File createImageFile() throws IOException{
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
    String imageFileName = "IMG_" + timeStamp + "_";
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    File image = File.createTempFile(imageFileName, ".jpg", storageDir);
    imageFilePath = image.getAbsolutePath();
    return image;
}

其中imageFilePath用于保存文件的路径。

打开相机时,设置把捕获到的图片Extra保存到FileProvider获取的Uri路径里。openCameraIntent修改如下:

private static final int REQUEST_CAPTURE_IMAGE = 100;

private void openCameraIntent() {
   Intent pictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
   if(pictureIntent.resolveActivity(getPackageManager()) != null){ 
        File photoFile = null;
        try {
            photoFile = createImageFile();
        } catch (IOException ex) {
            e.printStackTrace();
            return;
        }      
        if (photoFile != null) {
            Uri photoURI = FileProvider.getUriForFile(this,getPackageName() +".provider",photoFile);
            pictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,photoURI);
            startActivityForResult(pictureIntent,REQUEST_CAPTURE_IMAGE);
        }
   }
}

在打开相机时做了这几件事:

  1. 新建了临时文件phoneFile
  2. 使用FileProvider获取文件的Uri
  3. 设置pictureIntent的Extra输出URI
  4. 打开相机

使用FileProvider需要在AndroidManifest.xml声明provider:

<application>
   ...
   <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/file_paths">
        </meta-data>
    </provider>
    ...
</application>

在res/xml/创建file_paths.xml文件,如容如下:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images"  
      path="Android/data/com.example.package.name/files/Pictures" />
</paths>

onActivityResult处理拍照捕获图片的结果修改如下:

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

    if (requestCode == REQUEST_IMAGE) {
      if (resultCode == RESULT_OK) {
        imageView.setImageURI(Uri.parse(imageFilePath));
      }
      else if (resultCode == RESULT_CANCELED) {
        Toast.makeText(this, "取消拍照", Toast.LENGTH_SHORT).show();
      }
    }
  }

它不再是直接使用Bitmap,而是使用URI来访问图片。