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);这句,要不然还是拿不到图片的,以上。

原创粉丝点击