Android 调用系统相机,解决回调的resultCode一直都是0的问题;并通过Matisse(知乎图片选择框架)来选择图片

在很多项目中,要使用到相机的拍照、相册的预览、选择;今天在这里就总结一下使用方法;废话不多说,上代码了!

一:调用Android 原生相机拍照:

 /**
     * 调用系统相机拍照
     */
    public void getPicFromCamera() {
        private Uri mOriginUri;
        private String mCurrentPath;
        private File tempFile;

        //用于保存调用相机拍照后所生成的文件
        //照片的路径
        mCurrentPath = FileUtil.getImgpath(String.valueOf(System.currentTimeMillis()));
        //跳转到调用系统相机
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        //判断版本
        if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.CAMERA) !=
                PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission
                    .CAMERA}, 1);
            Toast.makeText(mContext, "请前往设置中打开拍照", Toast.LENGTH_SHORT).show();
        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                mOriginUri = FileProvider.getUriForFile(getApplication(), getApplication()
                                .getPackageName() + ".FileProvider",
                        new File(mCurrentPath));
                intent.putExtra(MediaStore.EXTRA_OUTPUT, mOriginUri);
            } else {
                intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile));
            }
            startActivityForResult(intent, CAMERA_REQUEST_CODE);
        }
    }

其中 getPackageName() + ".FileProvider",一定要与清单文件中的报名一致(具体生成步骤,往下看)。

FileUtil中生成文件的方法:

并解决拍照回调的resultCode返回都是0的问题,就是生成文件的时候,要加上file.getParentFile(),

原因是在创建拍照文件的时候路 file不存在,调用 file.mkdirs() , 最终创建的xxx.jpeg 是文件夹而非文件。

详细的原因,给大家推荐一个地址:https://blog.csdn.net/qq_21199331/article/details/83042001

  //获取图片存储的根目录
    public static String getImgDIrectory() {
        return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ?
                mSdRootPath + IMG_PATH : mDataRootPath + IMG_PATH;

    }

    public static String getImgpath(String imgName) {
        File file = new File(getImgDIrectory());
        if (!file.exists()) {
            file.getParentFile().mkdirs(); // getParentFile()
            //注意此处创建文件调用getParentFile()再调用    mkdirs()
        }
        return getImgDIrectory() + imgName + IMG_SUFFIX;
    }

其中还要有Android 版本的判断,来使用系统的文件共享FileProvider,配置如下:

1、在清单文件中添加:

 <!-- Android 7.0 文件共享配置,必须配置 -->
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.project.evaluationmobile.FileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

2、在res目录下创建xml文件,在xml中创建file_paths.xml文件,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<paths>

    <!-- 这个是保存拍照图片的路径,必须配置。 -->
    <external-path path="MyPet/" name="MyPetRoot" />
    <external-path name="sdcard_root" path="."/>

    <external-path name="ext_root" path="/"  />
</paths>

二:相册选择照片:(使用知乎的图片选择器,更多的api,可以查看源文档)

导入依赖:

//图片选择器
    api 'com.zhihu.android:matisse:0.4.3'
 /*
        从相册中选择照片
     */
    public void selectMyPhoto() {

        if (ContextCompat.checkSelfPermission(mContext, Manifest.permission
                .READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission
                    .READ_EXTERNAL_STORAGE}, 1);
            Toast.makeText(mContext, "请前往设置中打开读取权限", Toast.LENGTH_SHORT).show();
        } else {
            Matisse.from(this)
                    .choose(MimeType.allOf())//图片类型
                    .countable(true)//true:选中后显示数字;false:选中后显示对号
                    .maxSelectable(9)//可选的最大数
                    .capture(false)//选择照片时,是否显示拍照
                    .captureStrategy(new CaptureStrategy(true, "com.project.evaluationmobile" +
                            ".FileProvider"))//参数1 true表示拍照存储在共有目录,false表示存储在私有目录;参数2与
                    // AndroidManifest中authorities值相同,用于适配7.0系统 必须设置
                    .imageEngine(new GlideEngine())//图片加载引擎
                    .forResult(REQUEST_CODE_CHOOSE);//
        }
    }

好了,接下来就是回调了。相关的结实都在注释中写出来了。

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
         List<Uri> result;
        
        switch (requestCode) {
            case REQUEST_CODE_CHOOSE: // 选择照片
                if (resultCode == RESULT_OK) {
                    // 所选择的图片的uri的集合
                    result = Matisse.obtainResult(data);
                    Log.d("photo", result.toString() + "++++++++++===========");
                    for (int i = 0; i < result.size(); i++) {
                       // 可以通过for循环来得到我们所选中图片的uri,来进行相应的操作
                    }
                }
                break;
            case CAMERA_REQUEST_CODE:// 相机拍照
                if (resultCode == RESULT_OK) {
                    // 图片拍照完成,图片的路径就是我们一开始定义的路径:mCurrentPath
                    // 依次来完成相应的操作
                }
                break;
            default:
        }
    }

,在这方面,难免会遇到文件的处理、Uri等。在文章的后边,我会添加上我使用的两个工具类,希望对各位有用!

三、图片的预览、查看

这里给大家一个网址,自己查看吧。

https://blog.csdn.net/PenTablet/article/details/88552819

 

好了,接下来,就是我使用的两个工具类了,

FileUtil:
package com.project.evaluationmobile.util;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Environment;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/***
 *
 */
public class FileUtil {
    //SD卡根路径
    private static String mSdRootPath = Environment.getExternalStorageDirectory().getPath();

    //手机的缓存根目录
    private static String mDataRootPath = "";

    //保存图片的目录
    private final static String IMG_PATH = "/Evaluation/image";
    private final static String IMG_SUFFIX = ".png";


    public FileUtil(Context context) {
        mDataRootPath = context.getCacheDir().getPath();
    }

    //获取图片存储的根目录
    public static String getImgDIrectory() {
        return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ?
                mSdRootPath + IMG_PATH : mDataRootPath + IMG_PATH;

    }

    public static String getImgpath(String imgName) {
        File file = new File(getImgDIrectory());
        if (!file.exists()) {
            file.getParentFile().mkdirs(); // getParentFile()
            // 一定要加上这个参数,防止生成的不是文件夹,来解决resultCode返回都是0的问题
        }
        return getImgDIrectory() + imgName + IMG_SUFFIX;
    }

    //图片保存到本地,--返回图片的路径
    public static String saveImg(ByteArrayOutputStream bos) {
        FileOutputStream fos = null;
        String path = getImgpath(String.valueOf(System.currentTimeMillis()));
        File file = new File(path);
        try {
            if (!file.exists()) {
                file.createNewFile();
            }
            fos = new FileOutputStream(file);
            fos.write(bos.toByteArray());
            fos.flush();
        } catch (IOException e) {
            path = "";
            e.printStackTrace();
        } finally {
            try {
                if (fos != null)
                    fos.close();
                if (bos != null)
                    bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return path;

    }

    public static boolean saveImageToGallery(Context context, Bitmap bmp) {
        // 首先保存图片
        String storePath = getImgpath(String.valueOf(System.currentTimeMillis()));
        File appDir = new File(storePath);
        if (!appDir.exists()) {
            appDir.mkdir();
        }
        String fileName = System.currentTimeMillis() + ".jpg";
        File file = new File(appDir, fileName);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            //通过io流的方式来压缩保存图片
            boolean isSuccess = bmp.compress(Bitmap.CompressFormat.JPEG, 60, fos);
            fos.flush();
            fos.close();
            //把文件插入到系统图库
            //MediaStore.Images.Media.insertImage(context.getContentResolver(), file
            // .getAbsolutePath(), fileName, null);
            //保存图片后发送广播通知更新数据库
            Uri uri = Uri.fromFile(file);
            context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
            if (isSuccess) {
                return true;
            } else {
                return false;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }


}
ImageUtil:
package com.project.evaluationmobile.util;

import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.util.Log;

import java.io.ByteArrayOutputStream;

/**
 * @ClassName: ${type_name}
 * @Description: ${todo}
 * @author: ${libiao}
 * @date: ${date} ${time}
 * ${tags}
 */
public class ImageUtil {
    private static String Tag = "PATH";

    public static String getSmallBitmap(String filePath) {
        Log.d(Tag, "图片处理开始");

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filePath, options);
        options.inSampleSize = calculateInSampleSize(options, 1280, 720);
        Log.d(Tag, "图片分辨率压缩后" + options.inSampleSize + "");
        options.inJustDecodeBounds = false;
        //避免出现内存溢出的情况,进行相应的属性设置。
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        options.inDither = true;
        Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
        return compressAndSave(bitmap);
    }

    // 计算图片的缩放值
    private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }
        return inSampleSize;
    }

    // 这里是根据质量压缩.可以吧图片压缩到100K以下,然后保存到本地文件
    private static String compressAndSave(Bitmap image) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
        int options = 100;
        Log.d(Tag, baos.toByteArray().length / 1024 + "KB");
        System.out.println(baos.toByteArray().length / 1024 + "KB");
        while (baos.toByteArray().length / 1024 > 100) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
            baos.reset();// 重置baos即清空baos
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中
            options -= 10;// 每次都减少10
        }
        Log.d(Tag, "图片处理完成" + baos.toByteArray().length / 1024 + "KB");
        String path = FileUtil.saveImg(baos);
        image.recycle();

        Log.d(Tag, "压缩后的图片路径" + path);
        image = null;
        // 在这里已经压缩到100以下了,但是只要调用了decodeStream就又会涨到200K,所以在操作之前把图片先保存到本地
        // 如果需要返回一个bitmap对象,则调用如下方法
        // ByteArrayInputStream isBm = new
        // ByteArrayInputStream(baos.toByteArray());
        // 把压缩后的数据baos存放到ByteArrayInputStream中
        // Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
        // 把ByteArrayInputStream数据生成图片
        return path;
    }

    /**
     * @param context
     * @param uri
     * @return
     * @Title: getPhotoPath
     * @Description: 根据Uri得到该图片的路径(兼容4.4)
     * @return: String
     */
    public static String getPhotoPath(final Context context, final Uri uri) {
        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
        // DocumentProvider
        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageDirectory() + "/" + split[1];
                }
            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {

                final String id = DocumentsContract.getDocumentId(uri);
                final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

                return getDataColumn(context, contentUri, null, null);
            }
            // MediaProvider
            else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                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;
                }

                final String selection = "_id=?";
                final String[] selectionArgs = new String[]{split[1]};

                return getDataColumn(context, contentUri, selection, selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {

            // Return the remote address
            if (isGooglePhotosUri(uri))
                return uri.getLastPathSegment();

            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }

        return null;
    }

    private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {

        Cursor cursor = null;
        final String column = "_data";
        final String[] projection = {column};

        try {
            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                final int index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(index);
            }
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is ExternalStorageProvider.
     */
    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());
    }

    /**
     * @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());
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is Google Photos.
     */
    private static boolean isGooglePhotosUri(Uri uri) {
        return "com.google.android.apps.photos.content".equals(uri.getAuthority());
    }

}

好了,今天就分享到这里,谢谢~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值