1.使用摄像头拍照
代码中getExternalCacheDir()方法,获取的是应用关联缓存目录。我们要使用此目录来存放图片,为什么不用SD卡的其他目录,因为从Android 6.0开始,读写sd卡为危险权限,使用其他目录则需要运行时权限。(在android 7.1.1中使用getExternalCacheDir()目录,创建文件被禁止,应该也是需要运行时权限。使用geCacheDir()目录,创建文件不会被禁止。)
代码中有一处判断系统版本,是因为从Android 7.0系统开始,直接使用本地真实路径Uri被认为是不安全的,为了解决这个问题我们需要使用FileProvider。
take_photo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//用来存放拍摄的照片
File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
//文件存在就删除
if (outputImage.exists()) {
outputImage.delete();
}
try {
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
//判断系统版本是否高于7.0
if (Build.VERSION.SDK_INT >= 24) {
//getUriForFile(),参数一:context、参数二:任意的唯一字符、参数三:file对象
imageUri = FileProvider.getUriForFile(Main6Activity.this
,"cn.xd.study.a6", outputImage);
} else {
//获取uri
imageUri = Uri.fromFile(outputImage);
}
//进行拍照
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
//设置输出路径
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, TAKE_PHOTO);
}
});
拍完照片后,我们在onActivityResult()中进行处理。
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
try {
//读取刚拍的照片,显示出来
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver()
.openInputStream(imageUri));
picture.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
实现拍照功能的代码已经写完了,接下来还需要配置一下provider。编辑AndroidManifest.xml文件,在application下添加provider。
<provider
<!--name为固定值-->
android:name="android.support.v4.content.FileProvider"
<!--authorities的值要与FileProvider.getUriForFile()中参数二相同-->
android:authorities="cn.xd.study.a6"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
<!--name为固定值-->
android:name="android.support.FILE_PROVIDER_PATHS"
<!--resource引用了a.xml文件,a.xml中设置了共享的路径-->
android:resource="@xml/a" />
</provider>
创建a.xml文件,在project目录方式下,项目名→app→src→main→res,在res文件下创建xml文件目录和a.xml文件。a.xml文件如下:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<!--name 任意,path 共享的具体路径,path为空表示共享整个sd卡-->
<external-path name="my_images" path=""/>
<!--使用getCacheDir()对应cache-path-->
<cache-path name="cache" path="" />
</paths>
基本完成了,还有个小尾巴,兼容android 4.4系统之前的版本,访问sd卡需要声明权限。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2.从相册中选择照片
为了更好的兼容性,下面的程序运行之前,需要使用运行时权限,运行时权限就不展示了(读写权限)。
//打开相册
private void openAlbum() {
Intent intent = new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
startActivityForResult(intent, CHOOSE_PHOTO);//CHOOSE_PHOTO=2
}
选择照片完成后,需要使用onActivityResult()方法来处理。
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CHOOSE_PHOTO) {
//判断版本是否大于4.4并且是否选择了照片,从而执行不同的方法
//这是由于从4.4版本开始,选取相册中的图片不再返回真实的uri,需要对uri进行解析
if (Build.VERSION.SDK_INT >= 19 && resultCode != 0) {
handleImageOnKitKat(data);
} else if (resultCode != 0) {
handleImageBeforeKitKat(data);
}
}
}
//4.4及版本以上,要对uri进行处理,才能获取到真实的路径
@TargetApi(19)//指定该方法用于4.4版本及以上版本
private void handleImageOnKitKat(Intent data) {
String imagesPath = null;
Uri uri = data.getData();
if (DocumentsContract.isDocumentUri(Main7Activity.this, uri)) {
//从android 7.0操作,
//content://com.android.providers.media.documents/document/image:40
//getDocumentId()获取的是ID,40
String docId = DocumentsContract.getDocumentId(uri);
//从相册选取图片,uri中的Authority为com.android.providers.media.documents。
if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
String id = docId.split(":")[1];
String selection = MediaStore.Images.Media._ID + "=" + id;
imagesPath = getImagesPath(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));
imagesPath = getImagesPath(contentUri, null);
}
//4.4模拟器选择图片,content://media/external/images/media/12
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
imagesPath = getImagesPath(uri, null);
//在4.4系统红米1s选择图片的uri
//file:///storage/sdcard1/DCIM/Camera/IMG_20170623_105806.jpg
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
imagesPath = uri.getPath();
}
displayImage(imagesPath);
}
private void handleImageBeforeKitKat(Intent data) {
Uri uri = data.getData();
String imagePath = getImagesPath(uri, null);
displayImage(imagePath);
}
//获取真实的路径
private String getImagesPath(Uri uri, String selection) {
String path = null;
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;
}
displayImage()方法用来展示图片。选取照片所需权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />