Android开发选取照片问题
本文主要记录使用手机自带相机拍照获取返回照片路径,以及从本地相册选取已有照片时返回Intent data;
数据处理 操作。(小米手机获取照片路径与其他手机不一致问题!)
一:使用相机时添加权限:
<!-- 调用相机权限 -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!-- SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
二 调取相机拍照:
1. 拍照获取图片,返回Bitmap对象,图片不会自动保存至本地:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 1);
使用此方法拍照时,返回结果Intent data ;data.getData()==null;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//...
Uri uri = data.getData();//此时uri为null
Bundle bundle = data.getExtras();//
if (bundle != null) {
//图片被保存在 bundle中返回,使用budle.get("data")获取bitmap对象
Bitmap photo = (Bitmap) bundle.get("data");
//todo:得到bitmap对象可以直接使用imgaeview展示,此时是缩略图
} else {
Toast.makeText(getApplicationContext(), "无法找到该图片!", Toast.LENGTH_LONG).show();
return;
}
//...
}
ps:如果像保存图片到本地需要单独设置保存得路径
/**
* 将bitmap保存为特定格式的图片
*
* @param bmp 需要保存的bmp
* @param desFilename 目的文件路径
* @param format 保存的图片格式, 如果为空则默认保存为jpg格式
* @param quality 是否进行质量压缩
* @param recycleBitmapSavedFile 是否在保存图片后回收bitmap
* @return 保存成功, 则返回true; 否则返回false
*/
public static boolean saveBitmap(Bitmap bmp, String desFilename, Bitmap.CompressFormat format,
boolean recycleBitmapSavedFile, int quality) {
try {
if (bmp == null || bmp.isRecycled() || TextUtils.isEmpty(desFilename)) {
return false;
}
File file = new File(desFilename);
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
if (file.exists())
file.delete();
file.createNewFile();
FileOutputStream outStream = new FileOutputStream(file);
if (format == null) {
format = Bitmap.CompressFormat.JPEG;
}
boolean result = bmp.compress(format, quality, outStream);
outStream.flush();
outStream.close();
if (recycleBitmapSavedFile) {
bmp.recycle();
bmp = null;
}
// 操作成功, 直接返回
return result;
} catch (IOException e) {
e.printStackTrace();
} catch (RuntimeException e) {
e.printStackTrace();
} catch (OutOfMemoryError e) {
e.printStackTrace();
}
return false;
}
2 自定义照片存储路径,需要注意自定义路径时返回Intent data 都为null :
![这里写图片描述](https://img-blog.csdn.net/20161213130517218?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ2l0aHViXzMwNjYyNTcx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
/**
* 两种拍照获取图片得方法
*/
private Uri photoUri;
@Override
public void onTakePhotoItemclick() {
//方法一:保存拍摄图片至手机默认相册中
SimpleDateFormat timeStampFormat = new SimpleDateFormat("yyyyMMddHHmmss");
filename = timeStampFormat.format(new Date());
ContentValues values = new ContentValues(); //使用本地相册保存拍摄照片
values.put(MediaStore.Images.Media.TITLE, filename);
photoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
// 设置 intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); photoUri = 保存图片得uri
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(intent, FLAG_TAKE_PHOTO);
/* // 方法二 自定义文件夹保存
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
//创建文件夹 在本地文件Pictures 目录下创建 自己得文件夹
File dir = new File(Environment.getExternalStorageDirectory()+ "/Pictures/image");
if (!dir.exists()) {
dir.mkdirs();
}
//照片名称
File file = new File(dir, new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".jpg");
photoUri = Uri.parse(file.getPath());
startActivityForResult(new Intent(MediaStore.ACTION_IMAGE_CAPTURE)
.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)), FLAG_TAKE_PHOTO);
} else {
showToast("请检查SDCard!");
}*/
}
如何获取imagePath:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == FLAG_CHOOSE_IMG && resultCode == RESULT_OK) { //处理选择照片返回
//todo:
} else if (requestCode == FLAG_TAKE_PHOTO && resultCode == RESULT_OK) { //处理拍照返回
//使用第一种方法拍照时处理图片路径
Uri uri = null;
String path = "";
Cursor cursor = null;
uri = photoUri;
if (uri != null) {
String[] proj = {MediaStore.Images.Media.DATA};
cursor = managedQuery(uri, proj, null, null,
null);
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
path = cursor.getString(column_index);
//在android 4.0及其以上的版本中,Cursor会自动关闭,不需要自己关闭。
if (cursor != null && !cursor.isClosed() && Build.VERSION.SDK_INT < 14) {
cursor.close();
}
}
// 第二种方法时:获取图片路径
if (photoUri != null) {//todo
path = photoUri.toString();
}
//todo: 得到 path 之后可以转换成bitmap 使用。
}
}
在上述方法二中因为是自定义路径所以图片地址是已知得因此直接将 photoUri 转化成String 就可以直接使用了。
三 直接选择本地现有图片
@Override
public void onChoosePhotoItemclick() {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, FLAG_CHOOSE_IMG);
}
处理返回数据Intent data
**PS:个别小米手机返回数据和其他手机不同(暂时无法确定是否时全部小米手机)以下是debug
下三星手机和小米手机在选择本地图片时数据对比。**
三星手机:
小米手机:
可以看到小米手机返回得直接是file:///文件绝对路径;因此在获取图片path
时使用以下判断:
/**
* Intent data 小米手机选择相册照片时返回数据
{ dat=file:///storage/emulated/0/DCIM/Camera/IMG_20161129_195938.jpg typ=image/jpeg }
//other 拍照返回 Intent data
{ dat=content://media/external/images/media/222494 }
* @param data
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Uri uri = null;
String path = "";
Cursor cursor = null;
if (requestCode == FLAG_CHOOSE_IMG && resultCode == RESULT_OK) { //处理选择照片返回
if (data != null && data.getData() != null) {
uri = data.getData();
if (!TextUtils.isEmpty(uri.getAuthority())) { //使用 getAuthority 做判断条件
String[] proj = {MediaStore.Images.Media.DATA};
cursor = managedQuery(uri, proj, null, null,
null);
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
path = cursor.getString(column_index);
}else{
path = uri.getPath(); //小米选择照片返回 data="file:///..." uri.getAuthority()==""
}
//todo:
}
} else if (requestCode == FLAG_TAKE_PHOTO && resultCode == RESULT_OK) { //处理拍照返回
}
学习记录,如有错误和不足,欢迎大家指出
最后贴出一个不错的库:一款用于在Android设备上获取照片(拍照或从相册、文件中选择)、裁剪图片、压缩图片的开源工具库
。https://github.com/crazycodeboy/TakePhoto