调用摄像头和相册完全解析

拍照获取图片流程

  1. 创建一个File对象,用于装相机拍下的照片,起名:output_image.jpg
  2. 放到当前应用关联缓存目录下,getCacheDir()/getExternalCacheDir()
  3. 以android 7.0 为界,用不同的方式将File转换成Uri对象
  4. 然后构建Intent ,传入Uri,隐式启动相机
  5. 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大神的注解,好狗的难,到底哪里没想明白???
过了个周末。。。。。那么久,,,,,继续写。。。

对不起,自己勉强明白了个大概,粗略的写在了下一篇博客里。不值得关注,有需要的还是自行查阅比较好。等我真正消化了,再好好真理一篇清晰易懂的。

继续相机

相册选取图片流程

  1. 获取读写权限
  2. 打开图库
  3. 处理返回结果

打开图库

获取权限有很多方式,自己选择喜欢的,我就直接说正题了

   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);
        }
    }
发布了48 篇原创文章 · 获赞 12 · 访问量 5万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章