Android相册选择图片、相机拍照上传功能实现(上)

6,911 阅读3分钟

本篇 Blog 记录从相册选择照片或拍照实现更换头像及上传功能的实现

功能实现分为上下两篇。上篇记录照片的选择及拍照,下篇记录上传功能的实现

先上效果图

下面就来说一下相册选择图片和相机拍照的实现

一、相册选择图片


相册选择图片很简单,只需要通过 Intent 设置拉起就可以了

  1. Intent 拉起相册
	/**
     * 打开相册
     *
     * @param type 打开类型区分码(type是我用来区分回调的)
     */
    private void openGallery(int type) {
        Intent gallery = new Intent(Intent.ACTION_PICK);
        gallery.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
        startActivityForResult(gallery, type);
    }

  1. onActivityResult 回调处理
	@Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        // 这里没有判断是否匹配,data为空 
        Glide.with(this).load(data.getData()).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.NONE).into(helpBinding.ivHelpImageFirst);
    }

就这几行代码,就可以实现拉起相册选择图片,下面实现拍照

二、相机拍照图片


准备工作

因为我们要读取存储给拍照图片一个存储位置,所以我们需要先创建 FileProvider,为什么要用 FileProvider 而不直接用 File 是因为,从 Android N 7.0 之后,为了保证 App 间传输文件的安全性,不在允许直接用 file:// 传递,会 Crash 并抛出 FileUriExposedException,所以要临时授予权限通过 URI 访问。(Ps:可能理解不到位,深入了解可自行查询,这里简单说明下)

所以,在正式写相机拍照之前,我们先搞一下 FileProvider。

FileProvider

FileProvider 的使用也比较简单。分为三步。

  1. AndroidManifest.xml 中定义 FileProvider
  2. 创建 XML 文件说明临时授予权限的路径
  3. 使用 FileProvider

下面作简单说明

第一步:

		<!-- 应用共享Provider -->
        <provider
            android:
            android:authorities="你的包名.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:
                android:resource="@xml/file_paths" />
        </provider>

分别说明下含义
name:FileProvider 继承自 ContentProvider,原来是 v4 下的包,现在都在 androidx 下了。
authorities:作用是用来标识,命名方式是 APP 包名 + provider 名的形式
exported:是否公开
grantUriPermissions:是否授予临时权限

然后是 meta-data,由于我们不能直接使用 File,而要使用 URI,那么就需要配置文件对真实存储位置做一个映射。这个 resource 就是我们的映射配置文件,也就是哪些路径要授权写在这文件中。

第二步:

在 res 目录下创建 xml 文件夹再创建 file_paths.xml 文件。位置:res/xml/file_paths.xml

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

因为我比较懒,就直接从根目录授权,用 . 表示。

第三步:

最后就在代码中使用了

	// 直接通过该方法就可以得到URI
	Uri uri = FileProvider.getUriForFile(this, "在AndroidManifest.xml中声明的标识", file));

OK,简单了解 FileProvider 后,继续正题。

三、相机正文

  1. 创建拍照存储路径
  2. 拉起相机拍照
  3. onActivityResult 回调处理

第一步:

我们要给拍出的照片一个存储路径才能存储

		// 创建照片存储目录 ScreenUtils.getFilePath方法是一个工具类,下面有具体代码
        File imgDir = new File(ScreenUtils.getFilePath(this, null));
        // 创建照片
        String photoName = System.currentTimeMillis() + ".png";
        File picture = new File(imgDir, photoName);
        if (!picture.exists()) {
            try {
                picture.createNewFile();
            } catch (IOException e) {
                Log.e(TAG, "choosePictureTypeDialog: 创建图片失败", e);
            }
        }
        // 该路径在回调时获取图片用到
        imgPath = picture.getAbsolutePath();

第二步:

创建 Intent 拉起相机

        // 调用相机拍照
        Intent camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        camera.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(this, "AndroidManifest中声明的fileprovider标识", picture));
        startActivityForResult(camera, type);

第三步:

回调逻辑处理

	@Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        // 拉起相机回调data为null,打开相册回调不为null,这里没有判空
        Glide.with(this).load(imgPath).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.NONE).into(imageView);
    }
                    

到此,从相册选择图片和从相机拍照都已经完成了。

完整代码 GitHub 地址

下篇 Blog 实现上传功能。

以下是参考:
Android N FileProvider 详解
FileProvider 使用