赞
踩
Tips:记得申请权限和做运行时权限处理
- btn.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- //在应用关联缓存目录中新建 output_image.jpg 图片文件,因为Android6.0之后,读取SDCard被列为危险权限,如将图片存放在
- //SD卡的任何其他目录,均需进行运行时权限处理,而使用应用关联目录则可跳过该步骤,同时应用卸载会删除该目录
- //具体路劲:/sdcard/Android/data/<pacaage name>/cache
-
- //创建File 对象,用于存储拍摄的照片,存储在手机SD 卡的应用关联缓存目录下
- File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
- try {
- if (outputImage.exists()) {
- outputImage.delete();
- }
- outputImage.createNewFile();
- } catch (IOException e) {
- e.printStackTrace();
- }
- //系统版本判断
- if (Build.VERSION.SDK_INT >= 24) {
- //系统版本高于 Android7.0,者调用 FileProvider.getUriForFile() 方法,将file对象转换为一个封装过的Uri对象,
- // 参数一:Context 参数二:任意唯一的字符串 参数三:file对象
- imageUri = FileProvider.getUriForFile(MainActivity.this, "com.cloudc.notificationtest.provider", outputImage);
- } else {
- //系统版本低于 Android7.0,就调用Uri.fromFile()方法,将file对象转换为Uri对象,该Uri对象标志着 output_image.jpg 图片
- //的真实路劲,1
- imageUri = Uri.fromFile(outputImage);
- }
- //启动相机程序 隐式调用系统相机
- Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
- //添加这一句表示对目标应用临时授权该Uri所代表的文件
- intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- //指定图片的输出地址
- intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
- startActivityForResult(intent, TAKE_PHOTO);
- }
- });
因为从 Android7.0 开始,直接使用本地真实路劲的 Uri 被认为是不安全的,会抛出一个FileUriExposedException 异常,而FileProvider则是一种特殊的内容提供器来对数据进行保护,可以选择行的将封装过的 Uri 共享给外部,从而提高了应用的安全性。
注意:在Android 4.4 之前,访问SD 卡的关联目录也是需要声明权限的,从4.4 系统开始不在需要权限声明
- <?xml version="1.0" encoding="utf-8"?>
- <paths xmlns:android="http://schemas.android.com/apk/res/android">
- <!--external-path 用来指定 Uri 共享,
- name 属性可随便填写,
- path 属性值表示共享的具体路径,为空表示将整个SD 卡共享
- path:你所共享的子目录。虽然name属性是一个URI路径片段,但是path是一个真实的子目录名。
- 注意,path是一个子目录,而不是单个文件或者多个文件。
- -->
- <external-path name="my_images"
- path="."/>
- </paths>
Manifest.xml文件
- ....
- <!--name 属性固定
- authorities 属性必须和代码中 FileProvider.getUriForFile()中的第二个参数一致
- -->
-
- <!--meta-data 中指定了Uri 共享路径,并引用了一个xml文件资源-->
- <provider android:name="android.support.v4.content.FileProvider"
- android:authorities="com.example.yhadmin.gank.test.Test2Activity.fileprovider"
- android:exported="false"
- android:grantUriPermissions="true">
- <meta-data
- android:name="android.support.FILE_PROVIDER_PATHS"
- android:resource="@xml/file_paths">
- </meta-data>
- </provider>
- ....
获取图片兼容方案:
前提得获取SDCard 读写权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
部分代码
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (requestCode) {
- case CHOOSE_PHOTO: {
- if (resultCode == RESULT_OK) {
- //判断手机系统版本号
- if (Build.VERSION.SDK_INT >= 19) {
- //4.4及以上系统使用此方法处理图片
- handleImageOnKitKat(data);
- } else {
- //4.4以下系统使用此方法处理图像
- handleImageBeforeKitKat(data);
- }
- }
- break;
- }
- default:
- break;
- }
- }
- //4.4以下系统使用此方法处理图像
- private void handleImageBeforeKitKat(Intent data) {
- Uri uri = data.getData();
- String imagePath = getImagePath(uri, null);
- displayImage(imagePath);
- }
-
- @TargetApi(19)//4.4及以上系统使用此方法处理图片
- private void handleImageOnKitKat(Intent data) {
- String imagePath = null;
- Uri uri = data.getData();
-
- Logger.t("test2Activity").d("URI:"+uri.toString());
-
- if (DocumentsContract.isDocumentUri(this, uri)) {
- //如果是 document 类型的 Uri,则通过 document id 处理
- String documentId = DocumentsContract.getDocumentId(uri);
-
- Logger.t("test2Activity").d("documentId:"+uri.toString());
-
- if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
- //解析出数字格式的 id
- String id = documentId.split(":")[1];
- String selection = MediaStore.Images.Media._ID + "=" + id;
- imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
- }
-
- } else if ("content".equalsIgnoreCase(uri.getScheme())) {
- //如果是 content 类型的 Uri,则使用普通方式处理
-
- Logger.t("test2Activity").d("content:"+uri.getScheme());
-
- imagePath = getImagePath(uri, null);
-
- } else if ("file".equalsIgnoreCase(uri.getScheme())) {
- //如果是 Fiel 类型的 Uri,直接获取图片路径即可
- Logger.t("test2Activity").d("uri.getScheme():"+uri.getScheme());
- imagePath = uri.getPath();
- }
-
- displayImage(imagePath);//加载图片并显示
- }
- //加载图片
- private void displayImage(String imagePath) {
- if (imagePath!=null){
- Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
- bindingView.picture.setImageBitmap(bitmap);
- }else {
- ToastHelper.show(Test2Activity.this,"获取图片失败!");
- }
- }
- //获取图片路径
- private String getImagePath(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;
- }
1、确认权限是否添加
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
- /**
- * Same as calling {@link #startActivityForResult(Intent, int, Bundle)}
- * with no options.
- *
- * @param intent The intent to start.
- * @param requestCode If >= 0, this code will be returned in
- * onActivityResult() when the activity exits.
- *
- * @throws android.content.ActivityNotFoundException
- *
- * @see #startActivity
- */
- public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
- startActivityForResult(intent, requestCode, null);
- }
- Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
- intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(filePath, TEMP_IMAGE_NAME)));
- startActivityForResult(intent, 1);
- 1、Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath();
- 2、 Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
- android:configChanges="orientation|keyboardHidden"
- android:screenOrientation="portrait"
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- outState.putString("file_path", mFilePath);
- super.onSaveInstanceState(outState);
- }
然后在onCreate()方法里,判断savedInstanceState不为空时,取出图片路径的值。
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- if (savedInstanceState != null) {
- mFilePath = savedInstanceState.getString("file_path");
- // your code here
- }
- }
网上看到另外一种恢复的方法。Activity没有重新创建,而是成员变量被回收了,当拍照返回时,在onActivityResult()方法中mFilePath为空。解决方法是从onRestoreInstanceState()方法恢复数据。这种情况暂时没遇到,做个记录。
- @Override
- protected void onRestoreInstanceState(Bundle savedInstanceState) {
- if (TextUtils.isEmpty(mFilePath)) {
- mFilePath = savedInstanceState.getString("file_path");
- }
- super.onRestoreInstanceState(savedInstanceState);
- }
- /**
- * 获取图片的旋转角度
- * @param path 图片的绝对路径
- */
- private int getBitmapDegree(String imagePath) {
- int degree = 0;
- try {
- // 从指定路径下读取图片,并获取其EXIF信息
- ExifInterface exifInterface = new ExifInterface(imagePath);
- // 获取图片的旋转信息
- int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
- ExifInterface.ORIENTATION_NORMAL);
- switch (orientation) {
- case ExifInterface.ORIENTATION_ROTATE_90:
- degree = 90;
- break;
- case ExifInterface.ORIENTATION_ROTATE_180:
- degree = 180;
- break;
- case ExifInterface.ORIENTATION_ROTATE_270:
- degree = 270;
- break;
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- return degree;
- }
进行图形变换如旋转、缩放、移动的操作,可以使用Matrix类来完成。如下代码展示了使用Matrix对图片旋转,生成新的Bitmap。
- /**
- * 将图片按照某个角度进行旋转
- * @param bitmap 需要旋转的图片
- * @param degree 旋转角度
- */
- public static Bitmap rotateBitmapByDegree(Bitmap bitmap, int degree) {
- Bitmap result = null;
- // 根据旋转角度,生成旋转矩阵
- Matrix matrix = new Matrix();
- matrix.postRotate(degree);
- try {
- // 将原始图片按照旋转矩阵进行旋转,并得到新的图片
- result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
- } catch (Exception e) {
- }
- if (bitmap != null && !bitmap.isRecycled()) {
- bitmap.recycle();
- bitmap = null;
- }
- return result;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。