Android 调起系统相机拍照
概述
比奇小说网 m.biqi.org
最近在看 nanChen 写的图片选择器 ImagePicker,感觉写得很不错,也打算把从中学到的东西写下来。很多时候,遇到一个好的框架能够降低开发成本这是好事。但是也要去了解其内部具体实现逻辑,说不定哪天你需要完成一个类似的小功能,你知道原理就能快速写出来,而不是引入整个框架。
本文讲其中的第一个功能:如何调起手机的相机拍照?
系统现有相机应用
对于如何调用系统现有应用,这里简单再说一下。在开发的应用中调用系统现有应用,需要使用 Intent 指定开启的应用的 Action 和 Category,然后通过 startActivity(Intent) 或者 startActivityForResult(Intent, int) 开启指定的 Activity,如果使用 startActivityForResult() 方法开启并需要返回值,再重写 onActivityResult(int, int, Intent) 即可。
先来看看系统现有相机应用的 AndroidManifest.xml 清单文件定义的 Activity:
<activityandroid:name="com.android.camera.Camera"android:clearTaskOnLaunch="true"android:configChanges="orientation|keyboardHidden"android:screenOrientation="landscape"android:taskAffinity="android.task.camera"android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" ><intent-filter><action android:name="android.intent.action.MAIN" /><categroy android:name="android.intent.category.DEFAULT" /><categroy android:name="android.intent.category.LAUNCHER" /></intent-filter><intent-filter><action android:name="android.media.action.IMAGE_CAPTURE" /><categroy android:name="android.intent.category.DEFAULT" /></intent-filter><intent-filter><action android:name="android.media.action.STILL_IMAGE_CAMERA" /><categroy android:name="android.intent.category.DEFAULT" /></intent-filter></activity><activityandroid:name="com.android.camera.VideoCamera"android:clearTaskOnLaunch="true"android:configChanges="origientation|keyboardHidden"android:label="@string/video_camera_label"android:screenOrientation="landscape"android:taskAffinity="android.task.camcorder"android:theme="@android:style/theme.Black.NoTitleBar.Fullscreen" ><intent-filter><action android:name="android.media.action.VIDEO_CAMERA" /><categroy android:name="android.intent.category.DEFAULT" /></intent-filter><intent-filter><action android:name="android.media.action.VIDEO_CAPTURE" /><categroy android:name="android.intent.category.DEFAULT" /></intent-filter></activity>
它定义了两个 Activity,com.android.camera.Camera 表示照相机,com.android.camera.VideoCamera 表示摄像机。从字面意思可以看出,为了捕获系统相机返回的数据,一般需要使用一下两个 Action 即可开启照相机与摄像机:
android.media.action.IMAGE_CAPTURE:Intent 的 Action 类型,从现有的相机应用中请求一张图片。
android.media.action.VIDEO_CAPTURE:Intent 的 Action 类型,从现有的相机应用中请求一段视频。
上面两个参数,均在 MediaStore 类中以静态常量的形式定义好了,分别是:MediaStore.ACTION_IMAGE_CAPTURE (相机) 和 MediaStore.ACTION_VIDEO_CAPTURE (摄像机)。
获取系统现有相机拍摄的图片
在新开启的 Activity 中,如果需要获取它的返回值,则需要使用 startActivityForResult(Intent,int) 方法打开 Activity,并重写 onActivityResult(int, int, Intent) 获取系统相机的返回数据,那么我们只需要在 onActivityResult() 中获取到返回值即可。
系统相机拍摄的照片,如果不指定路径,会保存在系统默认文件夹下,可以使用 Intent.getExtra() 方法得到,得到的是一个 Uri 地址,表示了一个内容提供者的地址。如果通过MediaStore.EXTRA_OUTPUT 指定了保存路径,那么通过 Intent.getExtra() 得到的将是一个空地址,但是既然是我们指定的地址,那么也不愁找不到它了。
但是如果是7.0以上,需要使用 FileProvider 来得到这个 uri 地址。
实现方案
说清楚流程之后,下面就是具体代码实现:
首先是在 AndroidManiFest.xml 下声明拍照权限:
<uses-permission android:name="android.permission.CAMERA" />
声明权限后,在开始拍照前,还是需要判断用户是否给了我们拍照的权限:
if (( mActivity).checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(mActivity, new String[]{Manifest.permission.CAMERA}, GalleryActivity.REQUEST_PERMISSION_CAMERA); } else {imagePicker.takePicture(mActivity, GalleryActivity.REQUEST_CODE_TAKE); }
如果用户没有给权限,那么需要申请权限,权限申请以后,会有一个回调通知开发者是否允许了,具体见下发的代码:
@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == REQUEST_PERMISSION_CAMERA) {if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {imagePicker.takePicture(this, REQUEST_CODE_TAKE);} else {showToast("权限被禁止,无法打开相机");}}}
权限允许之后,通过 imagePicker.takePicture 去拍照。下面看下拍照的具体代码逻辑:
/*** 拍照的方法*/public void takePicture(Activity activity, int requestCode) {Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);takePictureIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);if (takePictureIntent.resolveActivity(activity.getPackageManager()) != null) {if (Utils.existSDCard()) takeImageFile = new File(Environment.getExternalStorageDirectory(), "/DCIM/camera/");else takeImageFile = Environment.getDataDirectory();takeImageFile = createFile(takeImageFile, "IMG_", ".jpg");if (takeImageFile != null) {// 默认情况下,即不需要指定intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);// 照相机有自己默认的存储路径,拍摄的照片将返回一个缩略图。如果想访问原始图片,// 可以通过dat extra能够得到原始图片位置。即,如果指定了目标uri,data就没有数据,// 如果没有指定uri,则data就返回有数据! Uri uri;if (VERSION.SDK_INT <= VERSION_CODES.M) {uri = Uri.fromFile(takeImageFile);} else {/*** 7.0 调用系统相机拍照不再允许使用Uri方式,应该替换为FileProvider* 并且这样可以解决MIUI系统上拍照返回size为0的情况*/uri = FileProvider.getUriForFile(activity, "com.example.myapplication.provider", takeImageFile);//加入uri权限 要不三星手机不能拍照List<ResolveInfo> resInfoList = activity.getPackageManager().queryIntentActivities(takePictureIntent, PackageManager.MATCH_DEFAULT_ONLY);for (ResolveInfo resolveInfo : resInfoList) {String packageName = resolveInfo.activityInfo.packageName;activity.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);}}// Log.e("nanchen", ProviderUtil.getFileProviderName(activity)); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);}}activity.startActivityForResult(takePictureIntent, requestCode);}
关于 Intent.resolveActivity 作用,简单来说就是当你在调用第三方软件或者系统 Activity,类似打开相机,发送图片等隐式 Intent,是并不一定能够在所有的 Android 设备上都正常运行。通过该方法判断这个 intent 对应的 activity 是否存在,确保不会出现崩溃。
takeImageFile 是图片存储地址,在7.0以前,需要用 Uri.fromFile 进行处理。7.0之后的采用 FileProvider。下面介绍下 FileProvider 的使用方法:
注册
使用 FileProvider 需要在 AndroidManiFest.xml 里声明:
<providerandroid:name="android.support.v4.content.FileProvider"android:authorities="com.example.myapplication.provider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_path" /></provider>
这里是直接使用的 v4 包中的 FileProvider,我们也可以直接继承 FileProvider 类,适当重写重载函数,但不建议如此做。下面来介绍上面的几个设置:
name: provider 的类名,若使用默认的 v4 的 FileProvider 可使用 "android.support.v4.content.FileProvider",也可以设置为自定义的继承 FileProvider 的 provider 类;
authorities: 一个签名认证,可以自定义,但在获取 uri 的时候需要保持一致;
grantUriPermissions: 使用 FileProvider 的使用需要我们给流出的URI 赋予临时访问权限(READ 和 WRITE),该设置是允许我们行使该项权力;
meta-data: meta-data 配置的是我们可以访问的文件的路径配置信息,需要使用 xml 文件进行配置,FileProvider 会通过解析 xml 文件获取配置项,其中 name 名字不可改变为: android.support.FILE_PROVIDER_PATHS,resource 为配置路径信息的配置项目。
路径配置
可访问的路径配置可以在 res 中建立一个 xml 文件下面建立一个配置文件,格式如下:
<?xml version="1.0" encoding="utf-8"?> <paths><!--path:需要临时授权访问的路径(.代表所有路径)--><!--name:就是你给这个访问路径起个名字--><external-path name="cam" path="." /> </paths>
下面解释下:
<files-path/> 代表的根目录: Context.getFilesDir()
- <external-path/> 代表的根目录: Environment.getExternalStorageDirectory()
- <cache-path/> 代表的根目录: getCacheDir()
最后,将 uri 放到 MediaStore.EXTRA_OUTPUT 中。
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
拍照完成后,会回调 onActivityResult,在这里我们可以根据先前传的值将图片展示到 ImageView 中:
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {Log.i(TAG, "系统相机拍照完成,resultCode=" + resultCode + " " + requestCode);if (requestCode == REQUEST_CODE_TAKE) {Uri uri = Uri.fromFile(takeImageFile);iv_CameraImg.setImageURI(uri);} }
到此,调用系统相机拍照的过程到此就结束了。
Android 调起系统相机拍照相关推荐
- android代码调用相机,Android如何调用系统相机拍照
本文实例为大家分享了Android调用系统相机拍照的具体代码,供大家参考,具体内容如下 /** * 调用系统相机 */ private void takePhoto() { Uri uri = nul ...
- Android手机调用系统相机拍照、裁剪以及获取Url上传图片
前言 最近一个人在公司搞独立开发,遇到问题只能自己解决,虽然过程比较坎坷,但是收获还是颇多的,一个人也是要坚强滴,最近弄用户的头像遇到了一些小问题,虽然上一款应用有头像上传,但是发现了其中的一些小问题 ...
- Android多层嵌套Fragment中调用系统相机拍照以及裁剪的相关问题解决
多层嵌套Fragment中调用系统相机拍照.裁剪 最近公司项目有频繁使用相机拍照的需求,然后频繁的实际使用过程中遇到很多大大小小的坑,在此记录下. (ps.关于一些拍照后图片旋转.裁剪设置返回数据为t ...
- Android调用系统相机拍照并保存到指定位置
Android调用系统相机拍照并保存到指定位置 @Click(R.id.btn_takePhoto)void onclick() {Intent intent = new Intent(MediaSt ...
- Android开发 调用系统相机相册图片功能,解决小米手机拍照或者图片横竖相反问题,及小米手机相册图片路径问题
Android开发 调用系统相机相册图片功能,解决小米手机拍照或者图片横竖相反问题,及小米手机相册图片路径问题 1.调用相机,兼容7.0 AndroidManifest配置 <providera ...
- android 相机拍照返回,Android6.0机型上调用系统相机拍照返回的resultCode值始终等于0的问题...
版权声明:本文为博主原创文章,未经博主允许不得转载. 正常情况下调用系统相机拍照: 如果拍照后点击的是"确定"图标,返回的resultCode = -1(Activity.RESU ...
- android固定位置拍照,Android调用系统相机拍照并保存到指定位置
Android调用系统相机拍照并保存到指定位置 @Click(R.id.btn_takePhoto) void onclick() { Intent intent = new Intent(Media ...
- Android Webview 调起系统相机、相册
公司有个业务需求,需要在H5页中可以分别调起相同中的相机.相册.拿到该H5页看了一下,H5中调起相机和打开相册的源码分别是: #调起相机 <input type="file" ...
- android 调用系统相机拍照 获取原图
博客源址:android 调用系统相机拍照 获取原图 博客时间:2013-04-23 11:08 好吧,为了这个问题又折腾了一整天.之前在网上找来的方法,如果在onActivityResult中直接用 ...
最新文章
- 微信小程序setData()方法的使用
- 使用 Servlet 读取表单数据
- VTK:图像平面小部件用法实战
- 验证视图状态 MAC 失败
- iBiology |除了B站,这还有个专业的生科科普网站
- AE鱼眼镜头畸变扭曲修复插件RevisionFX RELens for Mac
- 太棒了!输入文本直接生成流程图
- 【算术、关系、逻辑、位、复合赋值、带副作用的、自增、自减、其它】运算符(学习笔记4--C语言运算符)
- 用XSLT和XML改进Struts
- EFK 配置geo-ip落地实践
- 7 大版块 | 全面解读与认知支付系统
- verilog 之数字电路 边沿检测电路
- 国内三大通信运营商频段制式
- 计算机启动到安全模式,电脑正常开机会进入安全模式怎么办
- html超链接自动下划线,html超链接下划线应该加入吗?
- 第三届“网鼎杯”官方资格赛圆满结束,问鼎之战即将开启!
- 【深度思考,极客大学Java进阶训练营
- 优秀的程序员——用批判性思维批判下
- python中global用法实例
- Git提交信息规范化