Android 打开相机和相册,适配(仅限单选照片)


最近在项目中要用到使用系统相机和相册,单选照片,并上传。现在总结一下其中遇到的坑…

一、打开相机

  • 1.正常情况下打开相机(低于6.0系统)
    这种情况打开相机没有过多的设置,只要在manifest中配置权限:相机权限、内存的读写权限就OK了。
//拍的照片存放的位置
File file = new File(Environment.getExternalStorageDirectory(), "/temp/" +  System.currentTimeMillis() + ".jpg");
if (!file.getParentFile().exists()) file.getParentFile().mkdirs();
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照
imageUri = Uri.fromFile(file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
activity.startActivityForResult(intent, SELECT_CAMERA);
  • 2.适配6.0
    2.1 由于6.0系统需要动态的请求权限,所以在manifest设置权限之后,还要在打开相机之前请求是否拥有权限,动态请求
        //适配6.0 动态请求权限
        final String permission = Manifest.permission.CAMERA;  //相机权限
        final String permission1 = Manifest.permission.WRITE_EXTERNAL_STORAGE; //写入数据权限
        //先判断是否被赋予权限,没有则申请权限
        if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(activity, permission1) != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {  //给出权限申请说明
                ActivityCompat.requestPermissions(activity,
                        new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, CAMERA_REQUEST_CODE);
            } else { //直接申请权限
                //申请权限,可同时申请多个权限,并根据用户是否赋予权限进行判断
                ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.CAMERA}, CAMERA_REQUEST_CODE);
            }
        } else {  //赋予过权限,则直接调用相机拍照
            //在此调用打开相机的代码
        }

2.2 在请求权限之后,要对请求做出反应(是否同意该权限)

 @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {  //申请权限的返回值
            case CAMERA_REQUEST_CODE:
                int length = grantResults.length;
                final boolean isGranted = length >= 1 && PackageManager.PERMISSION_GRANTED == grantResults[length - 1];
                if (isGranted) {  //如果用户赋予权限,则调用相机
                    //在此调用打开相机代码
                } else { //未赋予权限,则做出对应提示

                }
                break;
        }

        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
  • 3.适配7.0
    7.0系统特性
    这里写图片描述
    根据7.0的特性,在适配的时候需要使用provider来共享文件
    3.1 在manifest中声明provider,不会的可以百度,或者看博主之前的文章
    3.2
//7.0调用调用相机的provider
//MYAPP_CAMERA_PROVIDER_NAME值需要需要和在maifest中声明的provider的authorities值相同
    private static final String MYAPP_CAMERA_PROVIDER_NAME = "[你自己的provider的路径].myfileprovider";
 //在打开相机的时候加适配
 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
   imageUri = FileProvider.getUriForFile(activity, MYAPP_CAMERA_PROVIDER_NAME, file);
} else {
  imageUri = Uri.fromFile(file);
}
  • 4.合并起来
/**
     * 选择系统相机
     * 已增加适配7.0
     * 对于6.0的适配 权限,默认是拥有使用相机的权限
     *
     * @param activity
     */
    public void openCameraForPhoto(Activity activity) {
        //适配6.0 动态请求权限
        final String permission = Manifest.permission.CAMERA;  //相机权限
        final String permission1 = Manifest.permission.WRITE_EXTERNAL_STORAGE; //写入数据权限
        //先判断是否被赋予权限,没有则申请权限
        if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(activity, permission1) != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {  //给出权限申请说明
                ActivityCompat.requestPermissions(activity,
                        new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, CAMERA_REQUEST_CODE);
            } else { //直接申请权限
                //申请权限,可同时申请多个权限,并根据用户是否赋予权限进行判断
                ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.CAMERA}, CAMERA_REQUEST_CODE);
            }
        } else {  //赋予过权限,则直接调用相机拍照
            openCamera(activity);
        }
    }
    /**
     * 打开相机
     *
     * @param activity
     */
    private void openCamera(Activity activity) {
        //适配7.0 共享文件的uri改为由FileProvider获取
        file = new File(Environment.getExternalStorageDirectory(), "/temp/" + System.currentTimeMillis() + ".jpg");
        if (!file.getParentFile().exists()) file.getParentFile().mkdirs();
        Intent intent = new Intent();
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            imageUri = FileProvider.getUriForFile(activity, MYAPP_CAMERA_PROVIDER_NAME, file);
        } else {
            imageUri = Uri.fromFile(file);
        }
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
        activity.startActivityForResult(intent, SELECT_CAMERA);
    }
  • 5.拍照之后返回
     @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case SELECT_CAMERA://选择相机拍照返回
                if (resultCode == Activity.RESULT_OK) {
                   //上面定义的file和imageUri就是照片的
                }
                break;
            case SELECT_PHOTOALBUM://选择相册照片返回
                if (resultCode == Activity.RESULT_OK && data != null) {
                    if (takePhotoListener != null) {
                        takePhotoListener.takePhotoSuccess(getFileFromMediaUri(activity, data.getData()), data.getData());
                    } else {
                        takePhotoListener.takePhotoFailed("选择照片失败,请重试");
                    }
                }
                break;
        }
        super.onActivityResult(requestCode, resultCode, data);

    }

二、打开相册

  • 1.正常打开相册
        Intent intent;
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
            intent = new Intent();
            intent.setType("image/*");
            intent.setAction(Intent.ACTION_GET_CONTENT);
        } else {
            intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        }
        activity.startActivityForResult(intent, SELECT_PHOTOALBUM);
  • 2.选择一张照片返回,拿到照片
     @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case SELECT_PHOTOALBUM://选择相册照片返回
                if (resultCode == Activity.RESULT_OK && data != null) {
                    if (takePhotoListener != null) {
                        //选择的照片的uri
                        Uri selectUri=data.getData();
                    } else {
                        //"选择照片失败,请重试"
                    }
                }
                break;
        }
        super.onActivityResult(requestCode, resultCode, data);

    }

三、在此提供一个uri转为File的方法,同时进行质量压缩

/**
     * 通过Uri获取文件
     *
     * @param ac
     * @param uri
     * @return
     */
    public static File getFileFromMediaUri(Context ac, Uri uri) {
        if (uri.getScheme().toString().compareTo("content") == 0) {
            ContentResolver cr = ac.getContentResolver();
            Cursor cursor = cr.query(uri, null, null, null, null);// 根据Uri从数据库中找
            if (cursor != null) {
                cursor.moveToFirst();
                String filePath = cursor.getString(cursor.getColumnIndex("_data"));// 获取图片路径
                cursor.close();
                if (filePath != null) {
                    return new File(filePath);
                }
            }
        } else if (uri.getScheme().toString().compareTo("file") == 0) {
            return new File(uri.toString().replace("file://", ""));
        }
        return null;
    }

    /**
     * 通过uri获取图片并进行压缩
     *
     * @param uri
     */
    public static Bitmap getBitmapFormUri(Activity ac, Uri uri) throws FileNotFoundException, IOException {
        InputStream input = ac.getContentResolver().openInputStream(uri);
        BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
        onlyBoundsOptions.inJustDecodeBounds = true;
        onlyBoundsOptions.inDither = true;//optional
        onlyBoundsOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional
        BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
        input.close();
        int originalWidth = onlyBoundsOptions.outWidth;
        int originalHeight = onlyBoundsOptions.outHeight;
        if ((originalWidth == -1) || (originalHeight == -1))
            return null;
        //图片分辨率以480x800为标准
        float hh = 800f;//这里设置高度为800f
        float ww = 480f;//这里设置宽度为480f
        //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
        int be = 1;//be=1表示不缩放
        if (originalWidth > originalHeight && originalWidth > ww) {//如果宽度大的话根据宽度固定大小缩放
            be = (int) (originalWidth / ww);
        } else if (originalWidth < originalHeight && originalHeight > hh) {//如果高度高的话根据宽度固定大小缩放
            be = (int) (originalHeight / hh);
        }
        if (be <= 0)
            be = 1;
        //比例压缩
        BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
        bitmapOptions.inSampleSize = be;//设置缩放比例
        bitmapOptions.inDither = true;//optional
        bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional
        input = ac.getContentResolver().openInputStream(uri);
        Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
        input.close();
        return compressImage(bitmap);//再进行质量压缩
    }
    /**
     * 质量压缩方法
     *
     * @param image
     * @return
     */
    public static Bitmap compressImage(Bitmap image) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
        int options = 100;
        while (baos.toByteArray().length / 1024 > 100) {  //循环判断如果压缩后图片是否大于100kb,大于继续压缩
            baos.reset();//重置baos即清空baos
            //第一个参数 :图片格式 ,第二个参数: 图片质量,100为最高,0为最差  ,第三个参数:保存压缩后的数据的流
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中
            options -= 10;//每次都减少10
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片
        return bitmap;
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值