安卓中相机相册调用总结

这里写图片描述

最终效果图

界面很简单,两个Button一个imageView。

1.先看下点击拍照,因为6.0以上安卓增加了权限管理,我们这里我先做了一个权限申请:

//检查权限(6.0以上做权限判断)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {    
    if (mPermissionsChecker.lacksPermissions(PERMISSIONS)) {        
        startPermissionsActivity();    
    } else {        
        openCamera();    
    }
} else {    
    openCamera();
}

如果有权限,则直接打开系统相机:

/** 
* 打开系统相机 
*/
private void openCamera() {    
    File file = new FileStorage().createIconFile();    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {        
        imageUri = FileProvider.getUriForFile(MainActivity.this, "com.bugull.cameratakedemo.fileprovider", file);//通过FileProvider创建一个content类型的Uri    
    } else {        
        imageUri = Uri.fromFile(file);    
    }    
    Intent intent = new Intent();    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {        
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件    
    }    
    intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照    
    intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI    
    startActivityForResult(intent, REQUEST_CAPTURE);}

这里指定保存图片路径的时候,我们做了一个判断,如果运行设备的版本低于7.0,则调用Uri.fromFile(),可以获取到图片的本地真实路径。否则,就调用FileProvider.getUriForFile(),获取一个封装过的uri对象,这是因为从安卓7.0开始,直接使用本地真实路径被认为是不安全的,会抛出FileUriExposedExCeption异常,而FileProvider则是一种特殊的内容提供其,它使用了和内容提供器类似的机制来对数据进行保护,可以选择性地将封装过的Uri共享给外部,从而提高了应用的安全性。

上面我们提到了内容提供器,作为安卓四大组件之一,肯定是要在xml中进行注册的:

<provider    
   android:name="android.support.v4.content.FileProvider"    
   android:authorities="com.bugull.cameratakedemo.fileprovider"    
   android:grantUriPermissions="true"    
   android:exported="false">    
      <meta-data        
      android:name="android.support.FILE_PROVIDER_PATHS"        
      android:resource="@xml/file_paths" />
</provider>

provider标签里的 android:name的值是固定的。android:authorities的值要跟我们上面获取uri的时候一直,这里我使用的是:包名.fileprovider。exported:要求必须为false,为true则会报安全异常。grantUriPermissions:true,表示授予 URI 临时访问权限。标签里面是用来指定共享的路径。 android:resource=”@xml/file_paths”就是我们的共享路径配置的xml文件。

这里写图片描述

位置如图所示

接下来看看这个file_paths是如何配置的

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

external-path就是用来指定Uri共享的,name属性的值可以随便填写,path属性的值表示共享的具体位置,设置为空,就表示共享整个SD卡,由于我在sd上保存图片的时候创建了一个名字叫demo的文件夹,所以这里我写一个demo就OK了,具体情况,自己再配置哈,这里我就不多提了。

拍照完成了就是裁剪了,我们看下裁剪的代码:

/** 
 * 裁剪 
 */
private void cropPhoto() {    
    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(uri, "image/*");    
    intent.putExtra("crop", "true");    
    intent.putExtra("aspectX", 1);    
    intent.putExtra("aspectY", 1);    
    intent.putExtra("scale", true);    
    intent.putExtra("return-data", false);    
    intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);    
    intent.putExtra("outputFormat", 
    Bitmap.CompressFormat.JPEG.toString());    
    intent.putExtra("noFaceDetection", true);     
    startActivityForResult(intent, REQUEST_PICTURE_CUT);
}
参数数据类型描述
cropString发送裁剪信号
aspectXintX方向上的比例
aspectYintY方向上的比例
outputXint裁剪区的宽
outputYint裁剪区的高
scaleboolean是否保留裁剪比例
scalereturn-data是否将数据保留在bitmap中返回
MediaStore.EXTRA_OUTPUT URIString裁剪的图片保存的地址
outputFormatString图片输出格式
noFaceDetectionboolean是否取消人脸识别

调用手机拍照的差不多就是上面这些,下面我们如何看看获取系统相册的图片。


2.首先还是来获取权限,上面已经贴过代码了,这里就不再贴出来啦!

下面看看如何打开系统相册

/** 
 * 从相册选择 
 */
private void selectFromAlbum() {    
    Intent intent = new Intent(Intent.ACTION_PICK);    
    intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");    
    startActivityForResult(intent, REQUEST_PICK_IMAGE);
}

为了兼容老版本,下面我们做了一些判断,如果系统是4.4以上的手机就调用handleImageOnKitKat(),否则就调用

handleImageBeforeKitKat(),之所以这样子处理,是因为4.4之后选取中的图片不再返回真实的Uri了,而是封装过的Uri,所以在4.4以上,就要对这个Uri进行解析。

4.4以上的处理方式

@TargetApi(19)
private void handleImageOnKitKat(Intent data) {    
    imagePath = null;    
    imageUri = data.getData();    
    if (DocumentsContract.isDocumentUri(this, imageUri)) {        
        //如果是document类型的uri,则通过document id处理        
        String docId = DocumentsContract.getDocumentId(imageUri);        
         if("com.android.providers.media.documents".equals(imageUri.getAuthority())) {            
   String id = docId.split(":")[1];//解析出数字格式的id            
   String selection = MediaStore.Images.Media._ID + "=" + id;            
   imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);        
} else if ("com.android.downloads.documents".equals(imageUri.getAuthority())) {           
   Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));            
   imagePath = getImagePath(contentUri, null);        
}    
} else if ("content".equalsIgnoreCase(imageUri.getScheme())) {       
 //如果是content类型的Uri,则使用普通方式处理        
   imagePath = getImagePath(imageUri, null);    
} else if ("file".equalsIgnoreCase(imageUri.getScheme())) {        
//如果是file类型的Uri,直接获取图片路径即可        
   imagePath = imageUri.getPath();    
}    
   cropPhoto();
}

4.4以下的处理方式

private void handleImageBeforeKitKat(Intent intent) {    
    imageUri = intent.getData();    
    imagePath = getImagePath(imageUri, null);    
    cropPhoto();
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值