Android调用系统拍照并保存,适配(11)

1、创建图片管理工具类

/**
 * @introduction 图片捕获管理工具
 */
public class ImageCaptureManager {
    private final static String CAPTURED_PHOTO_PATH_KEY = "mCurrentPhotoPath";
    private final static String yyyy_MM_dd_HH_mm_ss = "yyyyMMdd_HH时mm分ss";

    private Context mContext;
    /**
     * 当前图片路径,ImageCaptureManager传入Context对象初始化后调用createImageFile后才会有。
     */
    private String mCurrentPhotoPath;

    /**
     * 用于保存图片Uri
     * 因为文件系统的关系,使用uri来访问图片
     * 示例:content://com.android.providers.media.documents/document/image%3A1214406
     */
    private Uri mCurrentPhotoPathUri;


    public ImageCaptureManager(Context mContext) {
        this.mContext = mContext;
    }

    /**
     * 创建图片文件
     *
     * @return
     * @throws IOException
     */
    private File createImageFile() throws IOException {
        String timeStamp = new SimpleDateFormat(yyyy_MM_dd_HH_mm_ss).format(new Date());
        String imageFileName = "IMG_" + timeStamp;
        File storageDir = StorageUtil.getImageDir(mContext);
        File image = new File(storageDir, imageFileName + ".jpg");
        mCurrentPhotoPath = image.getAbsolutePath();
        mCurrentPhotoPathUri = CheckUtil.getUriForFile(mContext, image);
        Log.d("ImageCaptureManager", "createImageFile: " + mCurrentPhotoPathUri.toString());
        return image;
    }

    /**
     * 吊起系统的拍照
     *
     * @return
     * @throws IOException
     */
    public Intent dispatchTakePictureIntent() throws IOException {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // Ensure that there's a camera activity to handle the intent
        //11以前
        if (takePictureIntent.resolveActivity(mContext.getPackageManager()) != null) {
            // Create the File where the photo should go
            File photoFile = createImageFile();
            // Continue only if the File was successfully created
            if (photoFile != null) {
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCurrentPhotoPathUri);
            }
        } else {
            if (mContext.getPackageManager().hasSystemFeature(mContext.getPackageManager().FEATURE_CAMERA_ANY)) {
                //相机可用
                // Create the File where the photo should go
                File photoFile = createImageFile();
                // Continue only if the File was successfully created
                if (photoFile != null) {
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCurrentPhotoPathUri);
                }
            }

        }
        return takePictureIntent;
    }


    public String getCurrentPhotoPath() {
        return mCurrentPhotoPath;
    }

    public Uri getCurrentPhotoPathUri() {
        return mCurrentPhotoPathUri;
    }


    /**
     * 保存状态的方法,需要在调用此类的dispatchTakePictureIntent拉起图片模块的宿主调用
     *
     * @param savedInstanceState
     */
    public void onSaveInstanceState(Bundle savedInstanceState) {
        if (savedInstanceState != null && mCurrentPhotoPath != null) {
            savedInstanceState.putString(CAPTURED_PHOTO_PATH_KEY, mCurrentPhotoPath);
        }
    }

    /**
     * 回复状态的方法,需要在调用此类的dispatchTakePictureIntent拉起图片模块的宿主调用
     *
     * @param savedInstanceState
     */
    public void onRestoreInstanceState(Bundle savedInstanceState) {
        if (savedInstanceState != null && savedInstanceState.containsKey(CAPTURED_PHOTO_PATH_KEY)) {
            mCurrentPhotoPath = savedInstanceState.getString(CAPTURED_PHOTO_PATH_KEY);
        }
    }

    /**
     * 简单压缩图片
     *
     * @param filePath
     * @param targetPath 压缩后保存地址
     * @return
     */
    public static String compressImage(String filePath, String targetPath) {
        Bitmap image = getSmallBitmap(filePath);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        int options = 90;
        // 循环判断如果压缩后图片是否大于1M,大于继续压缩
        while (baos.toByteArray().length / 1024 > 1024) {
            // 重置baos即清空baos
            baos.reset();
            // 这里压缩options%,把压缩后的数据存放到baos中
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);
            // 每次都减少10
            options -= 10;
        }
        // 把压缩后的数据baos存放到ByteArrayInputStream中
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        // 把ByteArrayInputStream数据生成图片
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);

        File outputFile = new File(targetPath);
        try {
            if (!outputFile.exists()) {
                outputFile.getParentFile().mkdirs();
            } else {
                outputFile.delete();
            }
            FileOutputStream out = new FileOutputStream(outputFile);
            bitmap.compress(Bitmap.CompressFormat.JPEG, options, out);
        } catch (Exception e) {
        }
        return outputFile.getPath();
    }

    public static Bitmap getSmallBitmap(String filePath) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        //只解析图片边沿,获取宽高
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filePath, options);
        // 计算缩放比
        options.inSampleSize = calculateInSampleSize(options, 480, 800);
        // 完整解析图片返回bitmap
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(filePath, options);
    }

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

2、创建文件存储工具类

@SuppressWarnings("all")
public class StorageUtil {
    private static final String TAG = StorageUtil.class.getSimpleName();

    private StorageUtil() {
    }

    private enum TYPE {
        FILEDIR, FILEIMG, FILECACHE, FILEAUDIO
    }

    /**
     * 判断外存储是否挂载
     *
     * @return
     */
    public static boolean isExternalStorageWritable() {
        return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
    }

    private static File getAppDir(Context context, TYPE typeSub) {
        File rootDir;
        /**
         * ---关于Android10的分区适配----
         * 1.从 Android 4.4 到 Android 10,可以通过 Environment.getExternalStorageDirectory() 以 File Api 的方式读写。
         * 2.通过Context访问自己的私有目录,不需要读写权限,不管系统是哪个版本或者是外部存储还是内部存储。
         * 3.注意uri和真实路径的区别,查看res/xml/file_paths.xml中的示例。
         * 4.通过Storage Access Framework的Api不需要权限,可以访问其他应用创建的文件。
         * 不重要的知识:
         *      ① 6.0开始需要申请存储权限;
         *      ② Android 10开始可以做分区适配,不想做的话在配置清单application节点添加声明(requestLegacyExternalStorage = true)。
         *      不过②这种方式在Android11失效了,谷歌给了开发者一个的版本的适应时间,然后逼着你适配
         */
        File mFile;
        if (isExternalStorageWritable()) {//有外部存储
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {//Android 11以前
                //mFile👉外部存储根目录/项目名称
                mFile = new File(Environment.getExternalStorageDirectory(), UsageUtil.getAppName(context));
            } else {//Android11及以后,返回私有目录files
                //mFile👉外部存储当前项目目录/files/项目名称
                mFile = new File(context.getExternalFilesDir(null), UsageUtil.getAppName(context));
            }
        } else {//没有外部存储
            //mFile👉内部存储当前项目目录/files
            mFile = new File(context.getFilesDir(), UsageUtil.getAppName(context));
        }
        switch (typeSub) {
            case FILEDIR:
                rootDir = new File(mFile, "fs");
                break;
            case FILEIMG:
                rootDir = new File(mFile, "images");
                break;
            case FILECACHE:
                rootDir = new File(mFile, "caches");
                break;
            case FILEAUDIO:
                rootDir = new File(mFile, "audios");
                break;
            default:
                throw new IllegalStateException("Unexpected value: " + typeSub);
        }
        if (!rootDir.exists()) {
            rootDir.mkdirs();
        }
        return rootDir;
    }

    /**
     * 获取当前app文件存储目录
     *
     * @return
     */
    public static File getFileDir(Context context) {
        return getAppDir(context, TYPE.FILEDIR);
    }


    /**
     * 获取当前app图片文件存储目录
     *
     * @return
     */
    public static File getImageDir(Context context) {
        return getAppDir(context, TYPE.FILEIMG);
    }

    /**
     * 获取当前app缓存文件存储目录
     *
     * @return
     */
    public static File getCacheDir(Context context) {
        return getAppDir(context, TYPE.FILECACHE);
    }

    /**
     * 获取当前app音频文件存储目录
     *
     * @return
     */
    public static File getAudioDir(Context context) {
        return getAppDir(context, TYPE.FILEAUDIO);
    }

    /**
     * @param context
     * @return 真实路径"/storage/emulated/0/Android/data/包名/cache"
     */
    public static String getExternalCacheDir(Context context) {
        return context.getExternalCacheDir().getAbsolutePath();
    }

    /**
     * 创建一个文件夹, 存在则返回, 不存在则新建
     *
     * @param parentDirectory 父目录路径
     * @param directory       目录名
     * @return 文件,null代表失败
     */
    public static File getDirectory(String parentDirectory, String directory) {
        if (TextUtils.isEmpty(parentDirectory) || TextUtils.isEmpty(directory)) {
            return null;
        }
        File file = new File(parentDirectory, directory);
        boolean flag;
        if (!file.exists()) {
            flag = file.mkdir();
        } else {
            flag = true;
        }
        return flag ? file : null;
    }

    /**
     * 根据输入流,保存文件
     * 类型:直接覆盖文件
     *
     * @param file
     * @param is
     * @return
     */
    public static boolean writeFile(File file, InputStream is) {
        OutputStream os = null;
        try {
            //在每次调用的时候都会覆盖掉原来的数据
            os = new FileOutputStream(file);
            byte data[] = new byte[1024];
            int length = -1;
            while ((length = is.read(data)) != -1) {
                os.write(data, 0, length);
            }
            os.flush();
            return true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Log.e(TAG, e.getMessage());
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, e.getMessage());
            return false;
        } finally {
            closeStream(os);
            closeStream(is);
        }
    }

    /**
     * 删除文件或文件夹
     *
     * @param file
     */
    public static void deleteFile(File file) {
        try {
            if (file == null || !file.exists()) {
                return;
            }

            if (file.isDirectory()) {
                File[] files = file.listFiles();
                if (files != null && files.length > 0) {
                    for (File f : files) {
                        if (f.exists()) {
                            if (f.isDirectory()) {
                                deleteFile(f);
                            } else {
                                f.deleteOnExit();
                                Log.d(TAG, "删除文件 " + f.getAbsolutePath());
                            }
                        }
                    }
                }
            } else {
                file.deleteOnExit();
                Log.d(TAG, "删除文件 " + file.getAbsolutePath());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 保存文件
     *
     * @param inputStream  输入流,比如获取网络下载的字节流 ResponseBody.byteStream()
     * @param outputStream 输出流,比如FileOutputStream则是保存文件
     * @return
     */
    public static boolean saveFile(InputStream inputStream, OutputStream outputStream) {
        if (inputStream == null || outputStream == null) {
            return false;
        }
        try {
            try {
                byte[] buffer = new byte[1024 * 4];
                while (true) {
                    int read = inputStream.read(buffer);
                    if (read == -1) {
                        break;
                    }
                    outputStream.write(buffer, 0, read);
                }
                outputStream.flush();
                return true;
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            } finally {
                inputStream.close();
                outputStream.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 关闭流
     *
     * @param closeable
     */
    public static void closeStream(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                throw new RuntimeException("关闭流失败!", e);
            }
        }
    }


    /**
     * 通过uri拿到图片文件真实路径
     *
     * @param context
     * @param uri
     * @return
     * @deprecated Android10开始,MediaStore.Images.ImageColumns.DATA被标记为过期
     */
    @Deprecated
    public static String getImgRealFilePath(final Context context, final Uri uri) {
        if (null == uri) {
            return null;
        }
        final String scheme = uri.getScheme();
        String data = null;
        if (scheme == null) {
            data = uri.getPath();
        } else if (ContentResolver.SCHEME_FILE.equals(scheme)) {
            data = uri.getPath();
        } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
            final Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.Images.ImageColumns.DATA}, null, null, null);
            if (null != cursor) {
                if (cursor.moveToFirst()) {
                    final int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
                    if (index > -1) {
                        data = cursor.getString(index);
                    }
                }
                cursor.close();
            }
        }
        return data;
    }
}

3、检查工具类

public class CheckUtil {
    //与AndroidManifest.xml中FileProvider的权限字段一致
    public static final String AUTHS="AndroidManifest.xml中FileProvider的权限字段一致";
    public static Uri getUriForFile(Context context, File file) {
        if (context == null || file == null) {
            throw new NullPointerException();
        }
        Uri uri;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            uri = FileProvider.getUriForFile(context.getApplicationContext(), AUTHS, file);
        } else {
            uri = Uri.fromFile(file);
        }
        return uri;
    }

}

4、配置信息

public interface ImagePickerConstant {
    /**
     * 普通回调监听
     */
    interface SampleResultListener<T>{
        void onSuccess(T Data);
        void onFailure(T Data);
    }

    /**
     * 普通回调监听
     */
    interface NormalResultListener{
        void onSuccess();
        void onFailure();
    }

    interface GetSelectMode {
        int getSelectMode();
    }

    int REQUEST_TAKE_PHOTO = 2;
    /**
     * 预览请求状态码
     */
     int REQUEST_PREVIEW = 99;

    String mimeTypeImage="image/*";

    /** 图片选择模式,int类型 */
    String EXTRA_SELECT_MODE = "select_count_mode";
    /** 单选 */
    int MODE_SINGLE = 0;
    /** 多选 */
    int MODE_MULTI = 1;

    /** 最大图片选择次数,int类型 */
    String EXTRA_SELECT_COUNT = "max_select_count";
    /** 默认最大照片数量 */
    int DEFAULT_MAX_TOTAL= 9;

    /** 是否显示相机,boolean类型 */
    String EXTRA_SHOW_CAMERA = "show_camera";

    /** 默认选择的数据集 */
    String EXTRA_DEFAULT_SELECTED_LIST = "default_result";

    /** 筛选照片配置信息 */
    String EXTRA_IMAGE_CONFIG = "image_filter_configuration";

    /** 选择结果,返回为ArrayList<String>图片路径集合 */
    String EXTRA_RESULT = "pathList_result";

    /**
     * 预览的图片列表
     */
    String EXTRA_PHOTOS = "extra_photos";

    /**
     * 当前预览照片位置
     */
    String EXTRA_CURRENT_ITEM = "extra_current_item";

    /**
     * 预览界面是否显示删除Menu
     */
    String EXTRA_IS_SHOW_DELETE = "extra_is_show_delete";
}

最后在AndoridManifest.xml中添加provider_paths.xml

<provider
            android:name=".utils.FileProviderUtils"
            android:authorities="com.xxx.xxx.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>

xml代码

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <!--<external-path path="xxx(目录)/" name="files_path" />-->
    <root-path
        name="root_path"
        path="/" /> <!--内部路径相关api有关,涉及api较多-->
    <files-path
        name="my_files"
        path="fs/" /><!--与Context.getFilesDir()有关-->
    <files-path
        name="my_images"
        path="images/" />
    <files-path
        name="my_caches"
        path="caches/" />
    <files-path
        name="my_audios"
        path="audios/" />
    <external-path
        name="external"
        path="/" /><!--与Environment.getExternalStorageDirectory()有关-->
    <external-files-path
        name="my_files"
        path="fs/" /><!--与Context#getExternalFilesDir(String)和Context.getExternalFilesDir(null)有关-->
    <external-files-path
        name="my_images"
        path="images/" />
    <external-files-path
        name="my_caches"
        path="caches/" />
    <external-files-path
        name="my_audios"
        path="audios/" />
    <external-cache-path
        name="external_cache_path"
        path="/" /> <!--与Context.getExternalCacheDir()有关-->
</paths>

调用

    /**声明
     * 图片管理工具ImageCaptureManager
     */
    private ImageCaptureManager imageCaptureManager;

@Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        initView();
    }
private void initView() {
imageCaptureManager = new ImageCaptureManager(requireActivity());
//触发事件触发
Intent intent = null;
                try {
                    intent = imageCaptureManager.dispatchTakePictureIntent();
                    startActivityForResult(intent, ImagePickerConstant.REQUEST_TAKE_PHOTO);
                } catch (IOException e) {
                    e.printStackTrace();
                }
}
@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            /**相机拍照完成后,返回图片路径*/
            case ImagePickerConstant.REQUEST_TAKE_PHOTO:
                if (imageCaptureManager.getCurrentPhotoPath() != null) {

                    String images = imageCaptureManager.getCurrentPhotoPath();
                    
                }
                break;
            //通知刷新图库
            default:
                break;
        }
    }

就可以了

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Android Studio调用相机拍照并将照片保存到相册中,您需要执行以下步骤: 1. 首先,您需要在AndroidManifest.xml文件中添加相机和存储权限。这可以通过以下代码完成: ``` <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ``` 2. 接下来,您需要创建一个用于启动相机应用程序的Intent对象。您可以使用以下代码来创建Intent: ``` Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); ``` 3. 如果您想要将照片保存在相册中,您需要指定照片的存储位置。您可以使用以下代码来创建一个存储位置: ``` File photoFile = null; try { photoFile = createImageFile(); } catch (IOException ex) { // Error occurred while creating the File } ``` 在这个例子中,我们调用了一个名为createImageFile()的方法来创建一个新的空白图像文件,并返回一个File对象,该对象代表该文件。您需要实现该方法来创建一个唯一的文件名并指定文件的存储路径。 4. 在创建文件之后,您需要将其URI添加到Intent对象中。这可以通过以下代码完成: ``` Uri photoURI = FileProvider.getUriForFile(this, "com.your.package.name.fileprovider", photoFile); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); ``` 在这个例子中,我们使用了FileProvider来获取文件的URI。您需要将"com.your.package.name.fileprovider"替换为您应用程序的FileProvider授权的授权标识符。 5. 最后,您需要启动相机应用程序并在用户拍照后获取照片。这可以通过以下代码完成: ``` startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); ``` 在用户拍摄照片后,您需要在onActivityResult()方法中获取照片并将其保存到相册中。这可以通过以下代码完成: ``` @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) { galleryAddPic(); } } private void galleryAddPic() { Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); File f = new File(mCurrentPhotoPath); Uri contentUri = Uri.fromFile(f); mediaScanIntent.setData(contentUri); this.sendBroadcast(mediaScanIntent); } ``` 在这个例子中,我们调用了一个名为galleryAddPic()的方法来将照片添加到相册中。在该方法中,我们使用了一个名为MediaScannerConnection的类来扫描文件并更新媒体数据库。您需要实现该方法来将您的照片添加到相册中。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值