拍照获取图片流程
- 创建一个File对象,用于装相机拍下的照片,起名:output_image.jpg
- 放到当前应用关联缓存目录下,getCacheDir()/getExternalCacheDir()
- 以android 7.0 为界,用不同的方式将File转换成Uri对象
- 然后构建Intent ,传入Uri,隐式启动相机
- onActivityResult()得到返回值并处理
创建File对象
先创建一个file
//创建File对象,用于存储拍照后的图片
File outputImage = new File(getDiskCacheDir(this), "output_img.jpg");
//判断该目录下是否有文件存在
try {
if (outputImage.exists()) {
outputImage.delete();
}
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
放到当前应用关联缓存目录
获取可以使用的缓存地址:这里以sd卡的缓存目录为优先,sd卡不能用就用手机本地缓存目录。
- 应用关联缓存目录:SD卡中专门存放当前应用缓存数据的位置;
调用getExternalCacheDir()方法可以得到这个目录,在卸载程序的时候,这里数据可以被一起删除,而且用缓存目录的话即便是6.0以上的系统也不需要动态获取读写权限,因为不在内存而是缓存
/**
* 获取缓存地址,如果sd卡不存在就获取手机应用关联缓存目录
* 卸载程序可被删除,android6.0后不需要请求读写权限
* getExternalCacheDir():/sdcard/Android/data/<application package>/cache
* getCacheDir():/data/data/<application package>/cache
* @param context
* @return
*/
public String getDiskCacheDir(Context context) {
String cachePath = null;
//Environment.getExtemalStorageState() 获取SDcard的状态
//Environment.MEDIA_MOUNTED 只有改状态下才可以进行读写
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
|| !Environment.isExternalStorageRemovable()) {
//sd卡应用关联缓存目录
cachePath = context.getExternalCacheDir().getPath();
} else {
//手机应用关联缓存目录
cachePath = context.getCacheDir().getPath();
}
return cachePath;
}
将File转换成Uri对象
启动相机需要传入有效的Uri才行,现在还是File格式,需要转换。
- Android7.0 开始,直接使用本地真实路径的Uri被认为是不安全的,会抛出FileUriException异常。而FileProvider则是一种特殊的内容提供器,它使用了和内容提供器类似的机制来对数据进行保护。
//Android 7.0 开始,直接使用本地真实路径的Uri被认为是不安全的,而FileProvide则是一种特殊的内容提供器
if (Build.VERSION.SDK_INT >= 24) {
imgUri = FileProvider.getUriForFile(MainActivity.this, "com.yuanli.choosephoto.fileprovider", outputImage);
} else {
imgUri = Uri.fromFile(outputImage);
}
构建Intent ,传入Uri,隐式启动相机
//隐式启动相机程序
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri);
startActivityForResult(intent, TAKE_PHOTO);
onActivityResult()得到返回值并处理
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_CANCELED) {
return;
}
switch (requestCode) {
case TAKE_PHOTO:
if (resultCode == RESULT_OK) {
//将拍摄的照片展示出来
try {
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imgUri));
imgChoose.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
default:
break;
}
}
写着写着跑偏了,研究相册的时候需要动态申请权限,就想封装一个好点的,结果看各种文档一天就有过去了。还好差不多了。
被注解难住了,好难啊!看了各种文档了,想自己写不想用hy大神的库,可仿不出hy大神的注解,好狗的难,到底哪里没想明白???
过了个周末。。。。。那么久,,,,,继续写。。。
对不起,自己勉强明白了个大概,粗略的写在了下一篇博客里。不值得关注,有需要的还是自行查阅比较好。等我真正消化了,再好好真理一篇清晰易懂的。
继续相机
相册选取图片流程
- 获取读写权限
- 打开图库
- 处理返回结果
打开图库
获取权限有很多方式,自己选择喜欢的,我就直接说正题了
private void choosePhoto() {
//隐式启动相册
Intent intent = new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
startActivityForResult(intent, CHOOSE_PHOTO);
}
处理返回结果
启动Intent时传入数据是Uri格式,而Intent返回结果也是Uri格式的。只不过老规矩,4.4版本(19)为界,4.4以上返回的Uri不是图片真实的Uri,而是的封装过的。这里挺奇怪哈,拍照的时候给Intent传入Uri的时候,界限是7.0(24);不懂咋想的。反正记住别混为一谈了。
返回值判断:
case CHOOSE_PHOTO:
if(resultCode==RESULT_OK){
//判断手机系统版本号
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.KITKAT){
//4.4ji以上系统使用这个方法处理图片
handlerImageOnKitKat(data);
}else{
//4.4ji以下系统使用这个方法处理图片
handlerImageBeforeKitKat(data);
}
}
break;
/**
* android系统从4.4版本开始,选取相册中图片不再返回图片的真实的Uri了,
* 而是一个封装过的Uri,因此需要对这个Uri进行解析才行。
* @param data
*/
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private void handlerImageOnKitKat(Intent data) {
String imagePath=null;
Uri uri=data.getData();
imagePath = uriToPath(uri);
// startPhotoZoom(new File(imagePath), 350);
displayImage(imagePath);
}
private String uriToPath(Uri uri) {
String path = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (DocumentsContract.isDocumentUri(this, uri)) {
// 如果是document类型的Uri,则通过document id处理
String docId = DocumentsContract.getDocumentId(uri);
//如果authority是media格式的话,document id 还需要在进行一次解析
if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
String id = docId.split(":")[1]; // 解析出真正的数字格式的id
String selection = MediaStore.Images.Media._ID + "=" + id;
path = getImagePath(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.valueOf(docId));
path = getImagePath(contentUri, null);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
// 如果是content类型的Uri,则使用普通方式处理
path = getImagePath(uri, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
// 如果是file类型的Uri,直接获取图片路径即可
path = uri.getPath();
}
}
return path;
}
private String getImagePath(Uri uri, String selection) {
String path = null;
// 通过Uri和selection来获取真实的图片路径
Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
}
cursor.close();
}
return path;
}
/**
* android系统从4.4版本一下执行
* @param data
*/
private void handlerImageBeforeKitKat(Intent data) {
Uri uri = data.getData();
String imagePath = getImagePath(uri, null);
displayImage(imagePath);
Log.i("TAG", "file://" + imagePath + "选择图片的URI" + uri);
// startPhotoZoom(new File(imagePath), 350);
}
private void displayImage(String imagePath) {
if(imagePath!=null){
Bitmap bitmap=BitmapFactory.decodeFile(imagePath);
imgChoose.setImageBitmap(bitmap);
}
}