Android 调用系统相机拍照并获取图片

目录

  • 调用系统相机
  • 获取图片
    • 如何获取图片
      • 不指定存储目录
      • 指定存储目录
      • Android 7.0 以上的指定存储目录
      • FileProvider的简单使用
  • 参考链接

调用系统相机

调用系统相机很简单,只需要一个intent就可以跳转到相几界面,然后再通过onActivityResult来取得图片即可。

Intent openCameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 系统常量, 启动相机的关键
startActivityForResult(openCameraIntent, REQUEST_CODE_TAKE_PICTURE); // 参数常量为自定义的request code, 在取返回结果时有用

获取图片

重写onActivityResult方法,获取request_code.

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        switch (requestCode) {
            case REQUEST_CODE_TAKE_PICTURE:
               // 此处写“如何获取图片”...
                break;

        }
    }

如何获取图片

不指定存储目录

从上边可以知道打开相机的 Intent Action: MediaStore.ACTION_IMAGE_CAPTURE,该Action会打开照相机拍照然后返回结果。

如果在没有设置额外的控制图片存储路径的参数MediaStore.EXTRA_OUTPUT情况下,返回的结果将是一个小的Bitmap。

 Bitmap bm = (Bitmap) data.getExtras().get("data");
 ImageView.setImageBitmap(bm);

上述方法仅仅只适合于应用程序需要一张小的图片的时候。而且经过测试发现,保存图片后的图片与拍照时的预览图片对比后,发现前者失真严重。原因是现在相机的像素都很大,随便一张图片都上M,而Android系统分配给每个应用的最大内存是16M,如果直接将图片通过内存方式返回给调用者会占用过大的内存,因此这里得到的是一个处理后的缩略图。

指定存储目录

第二种方法获取图片,就是在intent里指定图片保存位置,这种方法取得的是原图。通过设置MediaStore.EXTRA_OUTPUT参数实现。此方法将保存原始图片到指定的Uri中,不会压缩, 代码如下:

// 打开相机Intent
 Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
 
 // 给拍摄的照片指定存储位置
String f = System.currentTimeMillis()+".jpg"; // 指定名字
Uri fileUri = Uri.fromFile(new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), f)); // 指定图片保存的uri,此处将图片保存在系统相册中
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); //指定图片存放位置,指定后,在onActivityResult里得到的Data将为null

// 启动相机
startActivityForResult(cameraIntent, REQUEST_CODE_CAMERA);

Android 7.0 以上的指定存储目录

上述“指定存储目录”的方法在一般情况下,运行没有任何问题;可是当把targetSdkVersion指定成24及之上并且在API>=24(Android 7.0以上)的设备上运行时,会抛出异常:

android.os.FileUriExposedException: 你指定的文件路径和文件名(即上边的fileUri) exposed beyond app through ClipData.Item.getUri()

原因:Android不再允许在app中把file://Uri暴露给其他app,包括但不局限于通过Intent或ClipData 等方法。原因在于使用file://Uri会有一些风险,比如:文件是私有的,接收file://Uri的app无法访问该文件。

在Android6.0之后引入运行时权限,如果接收file://Uri的app没有申请READ_EXTERNAL_STORAGE权限,在读取文件时会引发崩溃。

因此,Google提供了FileProvider,使用它可以生成content://Uri来替代file://Uri。

FileProvider的简单使用

FileProvider的简单使用可以参考:http://gelitenight.github.io/android/2017/01/29/solve-FileUriExposedException-caused-by-file-uri-with-FileProvider.html#fileprovider-1

我是参考这里边的讲述来使用FileProvider,具体方法不做赘述,仅贴代码。

provider_paths.xml



    

代码中:

// 打开相机Intent
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// 给拍摄的照片指定存储位置
String f = System.currentTimeMillis()+".jpg"; // 指定名字
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), f); // 指定文件
fileUri = FileProvider.getUriForFile(MainActivity.this, getPackageName() + ".provider", file); // 路径转换
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); //指定图片存放位置,指定后,在onActivityResult里得到的Data将为null
startActivityForResult(cameraIntent, REQUEST_CODE_CAMERA);

下边讲一下在用链接里的方法时遇到的一些问题。

  1. AndroidManifest.xml文件中添加provider时android:name="android.support.v4.content.FileProvider"无法识别的问题。
    解决方案:android.support.v4.content.FileProvider修改为androidx.core.content.FileProvider。Android库迁移到 androidx后造成 android.support.v4.content.FileProvider找不到。更换库。

  2. 打开相机时报错:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference

出现这个错误是因为AndroidManifest.xml处的android:authoritiesmActivity.getPackageName() + ".provider"不一致。

AndroidManifest.xml中:

android:authorities="${applicationId}.fileprovider"

代码中:

fileUri = FileProvider.getUriForFile(MainActivity.this, getPackageName() + ".provider", file); // 路径转换

将代码改为:

 fileUri = FileProvider.getUriForFile(MainActivity.this, getPackageName() + ".fileprovider", file); // 路径转换

问题解决。

参考链接

  1. http://gelitenight.github.io/android/2017/01/29/solve-FileUriExposedException-caused-by-file-uri-with-FileProvider.html#fileprovider-1
  2. https://blog.csdn.net/zcl875921355/article/details/88053119
  3. https://www.jianshu.com/p/55b817530fa3

你可能感兴趣的:(Android,学习)