当前位置: 首页 > news >正文

Android 调用系统相册、系统相机拍照

Android 调用系统相册、系统相机拍照工具类

第一步(准备工作):设置文件共享

1.1、指定 FileProvider

新建FileProvider类,名字随意,继承自FileProvider

public class MainFileProvider extends FileProvider {
}

1.2 、清单中添加FileProvider、对应权限

修改AndroidManifest.xml文件

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.myapp"><!--如果有多个摄像头默认使用后置摄像头--><uses-featureandroid:name="android.hardware.camera"android:required="false" /><uses-permission android:name="android.permission.CAMERA" /><!--Android10以下申请这个--><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><!--Android11()以上申请这个--><uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /><application...><providerandroid:name=".MainFileProvider"android:authorities="${applicationId}.fileProvider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/provider_paths" /></provider>...</application>
</manifest> 

1.3、指定可共享的目录

创建xml文件放于路径res/xml目录下,没有xm文件夹就手动创建
provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths><!--name: 名称标志字符串,不可以同名!--><!--path: 文件夹“相对路径”,完整路径取决于当前的标签类型。传空,代表你整个对应路径都可以用于共享--><root-pathname="root"path="" /><files-pathname="files"path="." /><cache-pathname="cache"path="." /><external-pathname="external"path="." /><external-files-pathname="external_files"path="." /><!-- 此标签需要 support-v4:25.0.0以上才可以使用--><external-cache-pathname="external_cache"path="." /></paths>

第二步(工具类):

1.1、工具类代码

PhotoImagePicker.java

/*** 调用系统拍照、系统相册* 使用前请自行进行权限申请* 拍照图片会保存在/storage/emulated/0/Android/data/<应用包名>/files/Pictures*/
public class PhotoImagePicker {private static volatile PhotoImagePicker instance = null;private PhotoPickCallback callback;private static final int PICK_IMAGE_CHOOSER_REQUEST_CODE = 200;private Uri outputFileUri;//拍照输出的uripublic static PhotoImagePicker getInstance() {if (instance == null) {synchronized (PhotoImagePicker.class) {if (instance == null)instance = new PhotoImagePicker();}}return instance;}/*** 启动照相机(Activity)*/public void startCamera(Activity activity, PhotoPickCallback callback) {this.callback = callback;outputFileUri = Uri.fromFile(new File(activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis() + ".jpg"));Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);intent.putExtra(MediaStore.EXTRA_OUTPUT, getIntentUri(activity, outputFileUri));activity.startActivityForResult(intent, PICK_IMAGE_CHOOSER_REQUEST_CODE);}/*** 启动照相机(Fragment)*/public void startCamera(Fragment fragment, PhotoPickCallback callback) {this.callback = callback;outputFileUri = Uri.fromFile(new File(fragment.requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis() + ".jpg"));Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);intent.putExtra(MediaStore.EXTRA_OUTPUT, getIntentUri(fragment.requireContext(), outputFileUri));fragment.startActivityForResult(intent, PICK_IMAGE_CHOOSER_REQUEST_CODE);}/*** 启动图库选择器(Activity)*/public void startGallery(Activity activity, PhotoPickCallback callback) {this.callback = callback;Intent intent = new Intent(Intent.ACTION_GET_CONTENT);intent.addCategory(Intent.CATEGORY_OPENABLE);intent.setType("image/*");activity.startActivityForResult(intent, PICK_IMAGE_CHOOSER_REQUEST_CODE);}/*** 启动图库选择器(Fragment)*/public void startGallery(Fragment fragment, PhotoPickCallback callback) {this.callback = callback;Intent intent = new Intent(Intent.ACTION_GET_CONTENT);intent.addCategory(Intent.CATEGORY_OPENABLE);intent.setType("image/*");fragment.startActivityForResult(intent, PICK_IMAGE_CHOOSER_REQUEST_CODE);}/*** 启动文件选择器(Activity)*/public void startChooser(Activity activity, String mime, PhotoPickCallback callback) {this.callback = callback;Intent intent = new Intent(Intent.ACTION_GET_CONTENT);intent.addCategory(Intent.CATEGORY_OPENABLE);intent.setType(mime);activity.startActivityForResult(intent, PICK_IMAGE_CHOOSER_REQUEST_CODE);}/*** 启动文件选择器(Fragment)*/public void startChooser(Fragment fragment, String mime, PhotoPickCallback callback) {this.callback = callback;Intent intent = new Intent(Intent.ACTION_GET_CONTENT);intent.addCategory(Intent.CATEGORY_OPENABLE);intent.setType(mime);fragment.startActivityForResult(intent, PICK_IMAGE_CHOOSER_REQUEST_CODE);}/*** 图片选择结果回调,在 {@link Activity#onActivityResult(int, int, Intent)} 中调用*/@SuppressWarnings("JavadocReference")public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {onActivityResultInner(activity, null, requestCode, resultCode, data);}/*** 图片选择结果回调,在 {@link Fragment#onActivityResult(int, int, Intent)} 中调用*/public void onActivityResult(Fragment fragment, int requestCode, int resultCode, Intent data) {onActivityResultInner(null, fragment, requestCode, resultCode, data);}private void onActivityResultInner(Activity activity, Fragment fragment, int requestCode, int resultCode, Intent data) {if (resultCode != Activity.RESULT_OK) {if (callback != null)callback.onCanceled();return;}Context context;if (activity != null) {context = activity;} elsecontext = fragment.getContext();if (context != null && requestCode == PICK_IMAGE_CHOOSER_REQUEST_CODE) {boolean isCamera = true;if (data != null && data.getData() != null) {String action = data.getAction();isCamera = action != null && action.equals(MediaStore.ACTION_IMAGE_CAPTURE);}Uri pickImageUri = isCamera || data.getData() == null ? outputFileUri : data.getData();handlePickImage(context, pickImageUri);}}/*** 选择图片结果回调*/private void handlePickImage(Context context, Uri imageUri) {if (callback != null)callback.onPickImage(handleUri(context, imageUri));outputFileUri = null;}/*** 兼容 Android N,Intent中不能使用 file:///**/private Uri getIntentUri(Context context, @NonNull Uri uri) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {return FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".fileProvider", new File(Objects.requireNonNull(uri.getPath())));} elsereturn uri;}/*** 处理返回图片的 uri,content 协议自动转换 file 协议,避免 {@link FileNotFoundException}*/private Uri handleUri(Context context, Uri uri) {String realPath = "";if (DocumentsContract.isDocumentUri(context, uri)) {//如果是document类型的Uri,则通过document id处理String docId = DocumentsContract.getDocumentId(uri);if ("com.android.providers.media.documents".equals(uri.getAuthority())) {String id = docId.split(":")[1]; // 解析出数字格式的idString selection = MediaStore.Images.Media._ID + "=" + id;realPath = getRealPathFromUri(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);} else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.parseLong(docId));realPath = getRealPathFromUri(context, contentUri, null);}} else if ("content".equalsIgnoreCase(uri.getScheme())) {//如果是content类型的Uri,则使用普通方式处理realPath = getRealPathFromUri(context, uri, null);} else if ("file".equalsIgnoreCase(uri.getScheme()))  //如果是file类型的Uri,直接获取图片路径即可realPath = uri.getPath();if (!TextUtils.isEmpty(realPath))return Uri.fromFile(new File(realPath));elsereturn uri;}/*** 获取文件的真实路径,比如:content://media/external/images/media/74275 的真实路径 file:///storage/sdcard0/Pictures/X.jpg* http://stackoverflow.com/questions/20028319/how-to-convert-content-media-external-images-media-y-to-file-storage-sdc*/private String getRealPathFromUri(Context context, Uri uri, String selection) {Cursor cursor = null;try {String[] proj = {MediaStore.Images.Media.DATA};cursor = context.getContentResolver().query(uri, proj, selection, null, null);if (cursor == null)return "";if (cursor.moveToFirst())return cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));return "";} catch (IllegalStateException e) {return e.getMessage();} finally {if (cursor != null)cursor.close();}}
}

1.2、回调类代码

PhotoPickCallback.java

public interface PhotoPickCallback {/*** 用户取消回调*/void onCanceled();/*** 图片返回回调*/void onPickImage(@Nullable Uri imageUri);
}

第三步(使用):

调用相机

                            PhotoImagePicker.getInstance().startCamera(this, new PhotoPickCallback() {@Overridepublic void onCanceled() {//用户取消}@Overridepublic void onPickImage(@Nullable Uri imageUri) {//TODO do some things}});

调用相册

              PhotoImagePicker.getInstance().startGallery(this, new PhotoPickCallback() {@Overridepublic void onCanceled() {//用户取消}@Overridepublic void onPickImage(@Nullable Uri imageUri) {//TODO do some things}});

设置回调回传

    @Overridepublic void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);PhotoImagePicker.getInstance().onActivityResult(this, requestCode, resultCode, data);}

注意事项:

  • 使用前请自行进行对应权限申请
  • 拍照图片默认保存在/storage/emulated/0/Android/data/<应用包名>/files/Pictures

相关文章:

  • MyBatis进行模糊查询时SQL语句拼接引起的异常问题
  • kubeadm快速部署K8S
  • 长亭雷池部署
  • 【云岚到家】-day03-1-门户等缓存方案选择
  • Django DetailView视图
  • 如何将NextJs中的File docx保存到Prisma ORM
  • 奇思妙想-可以通过图片闻见味道的设计
  • 数据网格和视图入门
  • Windows Docker Desktop 安装 postgres
  • openstack搭建
  • 如何开发高效服务(C++ )
  • Java——LinkedList
  • 基于C++、MFC和Windows套接字实现的简单聊天室程序开发
  • 软件服务中的 SLA 到底是什么?
  • React基础教程(07):条件渲染
  • [笔记] php常见简单功能及函数
  • 2019.2.20 c++ 知识梳理
  • 5、React组件事件详解
  • codis proxy处理流程
  • ES2017异步函数现已正式可用
  • Java比较器对数组,集合排序
  • Java知识点总结(JavaIO-打印流)
  • k个最大的数及变种小结
  • Laravel Mix运行时关于es2015报错解决方案
  • MySQL数据库运维之数据恢复
  • Netty 4.1 源代码学习:线程模型
  • Promise面试题2实现异步串行执行
  • SegmentFault 社区上线小程序开发频道,助力小程序开发者生态
  • Spring核心 Bean的高级装配
  • tensorflow学习笔记3——MNIST应用篇
  • text-decoration与color属性
  • 阿里云Kubernetes容器服务上体验Knative
  • 来,膜拜下android roadmap,强大的执行力
  • 聊聊springcloud的EurekaClientAutoConfiguration
  • 入职第二天:使用koa搭建node server是种怎样的体验
  • 腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 一道闭包题引发的思考
  • (02)Hive SQL编译成MapReduce任务的过程
  • (06)Hive——正则表达式
  • (09)Hive——CTE 公共表达式
  • (145)光线追踪距离场柔和阴影
  • (2022 CVPR) Unbiased Teacher v2
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (PWM呼吸灯)合泰开发板HT66F2390-----点灯大师
  • (solr系列:一)使用tomcat部署solr服务
  • (ZT)出版业改革:该死的死,该生的生
  • (附源码)ssm跨平台教学系统 毕业设计 280843
  • (接口封装)
  • (十五)devops持续集成开发——jenkins流水线构建策略配置及触发器的使用
  • (十一)JAVA springboot ssm b2b2c多用户商城系统源码:服务网关Zuul高级篇
  • (续)使用Django搭建一个完整的项目(Centos7+Nginx)
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • (译) 函数式 JS #1:简介
  • (中等) HDU 4370 0 or 1,建模+Dijkstra。