美文网首页
android从相册选择图片和拍照选择图片

android从相册选择图片和拍照选择图片

作者: 程序员小华 | 来源:发表于2018-12-26 14:49 被阅读0次

    在android开发中选择图片的方式大致可以分类两种,一种是从手机相册获取,另外一种则是通过调用手机拍照获得

    • 手机相册中获取,这种方式需要读取存储卡的权限
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    
    • 相机拍照获取,需要存储卡写入权限以及摄像头权限,并且调用系统相机还涉及到一个android 7.0应用间文件共享的问题,可根据之前的适配Android7.0应用间文件共享FileProvider 方式解决,此处不做多余解释
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.CAMERA"/>
    

    一.手机相册中获取,在android6.0以上需要处理权限动态申请的问题

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                        //未授权,申请授权(从相册选择图片需要读取存储卡的权限)
                        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, RC_CHOOSE_PHOTO);
                    } else {
                        //已授权,获取照片
                        choosePhoto();
                    }
    
    /**
    权限申请结果回调
    */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            switch (requestCode) {
                case RC_TAKE_PHOTO:   //拍照权限申请返回
                    if (grantResults.length == 2 && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                        takePhoto();
                    }
                    break;
                case RC_CHOOSE_PHOTO:   //相册选择照片权限申请返回
                    choosePhoto();
                    break;
            }
        }
    
    1.跳转系统相册获取图片的代码:
    public static final int RC_CHOOSE_PHOTO = 2;
    
    private void choosePhoto() {
            Intent intentToPickPic = new Intent(Intent.ACTION_PICK, null);
            intentToPickPic.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
            startActivityForResult(intentToPickPic, RC_CHOOSE_PHOTO);
        }
    
    2. 系统相册获取图片结果返回,这里使用Glide来显示图片
    @Override
        protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
    
            switch (requestCode) {
                case RC_CHOOSE_PHOTO:
                    Uri uri = data.getData();
                    String filePath = FileUtil.getFilePathByUri(this, uri);
    
                    if (!TextUtils.isEmpty(filePath)) {
                        RequestOptions requestOptions1 = new RequestOptions().skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.NONE);
                        //将照片显示在 ivImage上
                       Glide.with(this).load(filePath).apply(requestOptions1).into(ivImage);
                    }
                    break;
            }
        }
    

    二.拍照选择图片,也同样需要处理权限动态申请问题,与上面一样,不多加解释,下面是调用相机拍照的代码

        public static final int RC_TAKE_PHOTO = 1;
    
        private String mTempPhotoPath;
        private Uri imageUri;
    
        private void takePhoto() {
            Intent intentToTakePhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            File fileDir = new File(Environment.getExternalStorageDirectory() + File.separator + "photoTest" + File.separator);
            if (!fileDir.exists()) {
                fileDir.mkdirs();
            }
    
            File photoFile = new File(fileDir, "photo.jpeg");
            mTempPhotoPath = photoFile.getAbsolutePath();
            imageUri = FileProvider7.getUriForFile(this, photoFile);
            intentToTakePhoto.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
            startActivityForResult(intentToTakePhoto, RC_TAKE_PHOTO);
        }
    

    相机拍照返回结果:

    @Override
        protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
    
            switch (requestCode) {
                case RC_TAKE_PHOTO:
                    RequestOptions requestOptions = new RequestOptions().skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.NONE);
                    //将图片显示在ivImage上
                    Glide.with(this).load(mTempPhotoPath).apply(requestOptions).into(ivImage);
                    break;
            }
        }
    

    三.以上两步完成了从相机拍照选择图片以及从相册选择图片两种方式,但是在从相册选择照片的返回结果处理中还涉及到了从URI获取图片真实路径的方法 String filePath = FileUtil.getFilePathByUri(this, uri); 没有解释,从URI中获取图片的真实路径,不同机型的方式不同,下面是我自己使用过很多次,在多种手机的机型上面都可以正确获取真实路径的工具类

    public class FileUtil {
        /**
         * 根据URI获取文件真实路径(兼容多张机型)
         * @param context
         * @param uri
         * @return
         */
        public static String getFilePathByUri(Context context, Uri uri) {
            if ("content".equalsIgnoreCase(uri.getScheme())) {
    
                int sdkVersion = Build.VERSION.SDK_INT;
                if (sdkVersion >= 19) { // api >= 19
                    return getRealPathFromUriAboveApi19(context, uri);
                } else { // api < 19
                    return getRealPathFromUriBelowAPI19(context, uri);
                }
            } else if ("file".equalsIgnoreCase(uri.getScheme())) {
                return uri.getPath();
            }
            return null;
        }
    
        /**
         * 适配api19及以上,根据uri获取图片的绝对路径
         *
         * @param context 上下文对象
         * @param uri     图片的Uri
         * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
         */
        @SuppressLint("NewApi")
        private static String getRealPathFromUriAboveApi19(Context context, Uri uri) {
            String filePath = null;
            if (DocumentsContract.isDocumentUri(context, uri)) {
                // 如果是document类型的 uri, 则通过document id来进行处理
                String documentId = DocumentsContract.getDocumentId(uri);
                if (isMediaDocument(uri)) { // MediaProvider
                    // 使用':'分割
                    String type = documentId.split(":")[0];
                    String id = documentId.split(":")[1];
    
                    String selection = MediaStore.Images.Media._ID + "=?";
                    String[] selectionArgs = {id};
    
                    //
                    Uri contentUri = null;
                    if ("image".equals(type)) {
                        contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                    } else if ("video".equals(type)) {
                        contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                    } else if ("audio".equals(type)) {
                        contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                    }
    
                    filePath = getDataColumn(context, contentUri, selection, selectionArgs);
                } else if (isDownloadsDocument(uri)) { // DownloadsProvider
                    Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(documentId));
                    filePath = getDataColumn(context, contentUri, null, null);
                }else if (isExternalStorageDocument(uri)) {
                    // ExternalStorageProvider
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final String type = split[0];
                    if ("primary".equalsIgnoreCase(type)) {
                        filePath = Environment.getExternalStorageDirectory() + "/" + split[1];
                    }
                }else {
                    //Log.e("路径错误");
                }
            } else if ("content".equalsIgnoreCase(uri.getScheme())) {
                // 如果是 content 类型的 Uri
                filePath = getDataColumn(context, uri, null, null);
            } else if ("file".equals(uri.getScheme())) {
                // 如果是 file 类型的 Uri,直接获取图片对应的路径
                filePath = uri.getPath();
            }
            return filePath;
        }
    
        /**
         * 适配api19以下(不包括api19),根据uri获取图片的绝对路径
         *
         * @param context 上下文对象
         * @param uri     图片的Uri
         * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
         */
        private static String getRealPathFromUriBelowAPI19(Context context, Uri uri) {
            return getDataColumn(context, uri, null, null);
        }
    
        /**
         * 获取数据库表中的 _data 列,即返回Uri对应的文件路径
         *
         * @return
         */
        private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
            String path = null;
    
            String[] projection = new String[]{MediaStore.Images.Media.DATA};
            Cursor cursor = null;
            try {
                cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
                if (cursor != null && cursor.moveToFirst()) {
                    int columnIndex = cursor.getColumnIndexOrThrow(projection[0]);
                    path = cursor.getString(columnIndex);
                }
            } catch (Exception e) {
                if (cursor != null) {
                    cursor.close();
                }
            }
            return path;
        }
    
        /**
         * @param uri the Uri to check
         * @return Whether the Uri authority is MediaProvider
         */
        private static boolean isMediaDocument(Uri uri) {
            return "com.android.providers.media.documents".equals(uri.getAuthority());
        }
    
        private static boolean isExternalStorageDocument(Uri uri) {
            return "com.android.externalstorage.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri the Uri to check
         * @return Whether the Uri authority is DownloadsProvider
         */
        private static boolean isDownloadsDocument(Uri uri) {
            return "com.android.providers.downloads.documents".equals(uri.getAuthority());
        }
    }
    

    相关文章

      网友评论

          本文标题:android从相册选择图片和拍照选择图片

          本文链接:https://www.haomeiwen.com/subject/kaehlqtx.html