Android调用相机的那些事
来源:互联网 发布:sql数据库面试题 编辑:程序博客网 时间:2024/05/29 04:37
调用相机其实很简单,不过其实也有一些坑,现在记录下来:
先看调用代码:
private void toCamera() { File file = new FileStorage().createIconFile(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){ oriImageUri = FileProvider.getUriForFile(getActivity(), getActivity().getPackageName()+".fileprovider", file); L.d("文件"+oriImageUri); }else { oriImageUri = Uri.fromFile(file); } //这个intent的意图是拍照 Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //添加这一句表示对目标应用临时授权该Uri所代表的文件 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } //指定拍照的输出目录,也就是拍照完的存储位置 intent.putExtra(MediaStore.EXTRA_OUTPUT, oriImageUri); startActivityForResult(intent,CAMERA_REQUEST_CODE); //dialog.dismiss(); }
putExtra这个调用还是很重要的,它用来指定拍照的输入目录,来看谷歌文档的描述:
MediaStore.EXTRA_OUTPUT - This setting requires a Uri object specifying a path and file name where you’d like to save the picture. This setting is optional but strongly recommended. If you do not specify this value, the camera application saves the requested picture in the default location with a default name, specified in the returned intent’s Intent.getData() field.
下面是坑:
①Android7.0中尝试传递 file:// URI 会触发 FileUriExposedException,因为在Android7.0之后Google认为直接使用本地的根目录即file:// URI是不安全的操作,直接访问会抛出FileUriExposedExCeption异常崩溃.因此上面的代码加了适配,增加一个fileprovider来共享数据,直接说方案:
在manifest中添加provider:
<provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/></provider>
.fileprovider和provider_paths是自己命名的名字,provider_paths的实现如下:
<?xml version="1.0" encoding="utf-8"?><paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="."/></paths>
name是uri的根目录,path是存储路径的根目录,比生成文件的URI路径为:
content://${applicationId}.fileprovider/external_files
${applicationId}表示本项目的项目名和包名,我文件默认是建立在手机的外部存储卡,也就是
File external =Environment.getExternalStorageDirectory();
那么根据path的值,文件保存的根目录是外部存储卡的.目录也就是根目录。
②:Android6.0引入了动态权限管理,所以像以前一样直接在某个目录下建立文件(来保存拍照后的图片)是成功不了的,所以如果你直接来建一个文件:
File file = new File(Environment.getExternalStorageDirectory()+"/mydir/", "hello.png");
你会死的很惨,因为文件怎么也建立不了,怎么解决呢,那就是引入权限管理,具体我就不贴代码了。
下面说下拍照保存后,继续调用系统裁剪功能来裁剪照片的过程:
private void startPhotoZoom() { if(null == oriImageUri) { return; } File file = new FileStorage().createCropFile(); Uri outputUri = Uri.fromFile(file);//裁剪后图片保存地址 Intent intent = new Intent("com.android.camera.action.CROP"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } intent.setDataAndType(oriImageUri, "image/*"); intent.putExtra("crop", "true"); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); intent.putExtra("outputX",320); intent.putExtra("outputY",320); intent.putExtra("return-data", true); intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);//和上面一样,指定保存裁剪后图片的地址 startActivityForResult(intent, CROP_REQUEST_CODE); }
这里稍微说下intent的动作和数据,也是我自己的一个理解,在代码里面Intent(“com.android.camera.action.CROP”);是指定intent的动作,从名字可以看出是裁剪图片的动作,那么第二步也就是指定数据了,因为必须要有一些东西来进行“裁剪”的动作,数据也就是要裁剪的对象,对应
intent.setDataAndType(oriImageUri, “image/*”),这样相互配合,才是一个好的“意图“,后面又指定了裁剪后保存的位置,现在intent已经很完美了,去处理它:
bitmap = BitmapFactory.decodeStream(this.getActivity(). getContentResolver().openInputStream(outputUri));profile_image.setImageBitmap(bitmap);
上面文档说过存储的位置也可以不指定,如果不指定,该怎样写呢,以下是一个例子:
private void startPhotoZoom(Uri uri) { if (uri == null) { L.e("uri == null"); return; } Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, "image/*"); //设置裁剪 intent.putExtra("crop", "true"); //裁剪宽高比例 intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); //裁剪图片的质量 intent.putExtra("outputX", 320); intent.putExtra("outputY", 320); //发送数据 intent.putExtra("return-data", true); startActivityForResult(intent, RESULT_REQUEST_CODE); }
来看onActivityResult方法中:
public void onActivityResult(int requestCode, int resultCode, Intent data) { ... case RESULT_REQUEST_CODE: //有可能点击舍弃 if (data != null) { //拿到图片设置 setImageToView(data); } break;}private void setImageToView(Intent data) { Bundle bundle = data.getExtras(); if (bundle != null) { Bitmap bitmap = bundle.getParcelable("data"); profile_image.setImageBitmap(bitmap); } }
证明文档说的没错,确实可以不指定输出的图像,而通过Intent.getData() 可以拿到图片,不过注意一点,一定要有intent.putExtra(“return-data”, true);这句,要不然还是拿不到图片的,以上。
- Android调用相机的那些事
- Android调用系统相机的那些坑
- 系统相机调用的那些问题...
- 【Android】相机的简单调用
- Android下相机的调用
- 关于Android开发调用系统相机拍照的 一些事
- Android 图片的裁剪与相机调用
- android中相机的简单调用
- 调用Android相机拍照的问题
- 关于Android调用系统相机的问题
- Android两种相机的调用方式
- Android相机和本地图片的调用
- android 调用相机 照片旋转的解决方案
- Android 调用系统相机回调后的处理
- Android相机开发那些坑
- Android相机开发那些坑
- Android相机开发那些坑
- Android相机开发那些坑
- 以交互方式安装ESXi 6.0
- XenApp_XenDesktop_7.6实战篇之一:走进桌面虚拟化世界
- Spring Boot 系列(2) 配置文件的加载
- XenServer 6.5实战系列之七:Creating Windows Server 2012R2 VM
- XenServer 6.5实战系列之八:Creating a VM Template from an Existing VM
- Android调用相机的那些事
- Android 随笔集
- XenServer 6.5实战系列之九:Creating a VM Template from a VM Snapshot
- XenServer 6.5实战系列之十:Create VMs from a VM Template
- XenServer 6.5实战系列之十一:Install Update For XenServer 6.5
- XenApp_XenDesktop_7.6实战篇之二:基础架构准备
- XenApp_XenDesktop_7.6实战篇之三:AD、DNS服务器规划及部署
- [C++] effective_C++_条款03
- XenApp_XenDesktop_7.6实战篇之四:AD、DNS服务器高级配置