小工具知识网

当前位置: 首页 > 行业知识 > Android保存图片到相册,兼容Android10及以上版本

行业知识

Android保存图片到相册,兼容Android10及以上版本

2026-10-31 21:47:31 来源:互联网转载

Android 共享存储空间

访问共享存储空间中的媒体文件

1、MediaStore概述

MediaStore是android系统提供的一个多媒体数据库,专门用于存放多媒体信息的,通过ContentResolver即可对数据库进行操作。

  • MediaStore.Files: 共享的文件,包括多媒体和非多媒体信息;
  • MediaStore.Audio: 存放音频信息;
  • MediaStore.Image: 存放图片信息;
  • MediaStore.Vedio: 存放视频信息;

    每个内部类中都又包含了Media,Thumbnails和相应的MediaColumns,分别提供了媒体信息,缩略信息和操作字段。

    (1)MediaStore.Images.Media的使用——MediaStore.Images.Media.EXTERNAL_CONTENT_URI

    (2)MediaStore.Video.Media的使用——MediaStore.Video.Media.EXTERNAL_CONTENT_URI

    (3)MediaStore.Audio.Media的使用——MediaStore.Audio.Media.EXTERNAL_CONTENT_URI

    (4)MediaStore.Downloads的使用——MediaStore.Downloads.getContentUri(“external”)

    (5)MediaStore.Files的使用——MediaStore.Files.getContentUri(“external”)

    2、示例

    1、Android保存图片到相册,兼容Android10及以上版本:

        // 保存bitmap到相册,并兼容AndroidQ    public static boolean saveBitmap(Context context, Bitmap bitmap) {        if (bitmap == null) {            return false;        }        boolean isSaveSuccess;        if (Build.VERSION.SDK_INT = Build.VERSION_CODES.R) {                resolver.delete(uri, null);            }            return false;        }        return true;    }

    2、删除相册资源(Kotlin):

     /**     * 保存bitmap到相册,并兼容AndroidQ     */    fun getBitmapFileDir(): String {        return if (Build.VERSION.SDK_INT  

    3、MediaStore 扩展方法:

    /** * 和媒体相关的工具类 */public class MediaUtils {    /**     * 每页获取的媒体数据量(分页加载解决相册卡顿问题)     * */    private static final int PAGE_SIZE = 1000;    /**     * 添加到媒体数据库     * Add to media database     */    public static Uri saveVideo2Album(String videoPath, int videoWidth, int videoHeight,                                      int videoTime) {        File file = new File(videoPath);        if (file.exists()) {            Uri uri = null;            long dateTaken = System.currentTimeMillis();            ContentValues values = new ContentValues(11);            // 路径;            values.put(MediaStore.Video.Media.DATA, videoPath);            // 标题;            values.put(MediaStore.Video.Media.TITLE, file.getName());            // 时长            values.put(MediaStore.Video.Media.DURATION, videoTime * 1000);            // 视频宽            values.put(MediaStore.Video.Media.WIDTH, videoWidth);            // 视频高            values.put(MediaStore.Video.Media.HEIGHT, videoHeight);            // 视频大小;            values.put(MediaStore.Video.Media.SIZE, file.length());            // 插入时间;            values.put(MediaStore.Video.Media.DATE_TAKEN, dateTaken);            // 文件名;            values.put(MediaStore.Video.Media.DISPLAY_NAME, file.getName());            // 修改时间;            values.put(MediaStore.Video.Media.DATE_MODIFIED, dateTaken / 1000);            // 添加时间;            values.put(MediaStore.Video.Media.DATE_ADDED, dateTaken / 1000);            values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");            ContentResolver resolver = Utils.getApp().getContentResolver();            if (resolver != null) {                try {                    uri = resolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);                } catch (Exception e) {                    e.printStackTrace();                    uri = null;                }            }            if (uri == null) {                MediaScannerConnection.scanFile(Utils.getApp(), new String[]{videoPath}, new String[]{"video/*"}, new MediaScannerConnection.OnScanCompletedListener() {                    @Override                    public void onScanCompleted(String path, Uri uri) {                    }                });            }            return uri;        }        return null;    }    /**     * Add video record by android_Q api.     * AndroidQ以上,增加视频文件记录     *     * @param context      上下文,the context     * @param fileName     视频文件名称 the video file name     * @param fileType     视频文件类型 the video file type     * @param relativePath 相对路径 the relative path     * @param duration     文件时长,单位是毫秒The duration of the file, in milliseconds.     * @return String 类型的Uri. The String of Uri     */    public static String addVideoRecord_Q(Context context, String fileName, String fileType,                                          String relativePath, long duration) {        if (!AndroidVersionUtils.isAboveAndroid_Q()) {            return null;        }        if (TextUtils.isEmpty(relativePath)) {            return null;        }        relativePath = "Movies/" + relativePath;        ContentResolver resolver = context.getContentResolver();        //设置文件参数到ContentValues中        ContentValues values = new ContentValues();        //设置文件名        values.put(MediaStore.Video.Media.DISPLAY_NAME, fileName);        //设置文件描述,这里以文件名代替        values.put(MediaStore.Video.Media.DESCRIPTION, fileName);        //设置文件类型为image/*        values.put(MediaStore.Video.Media.MIME_TYPE, "video/" + fileType);        values.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000);        values.put(MediaStore.Video.Media.DATE_MODIFIED, System.currentTimeMillis() / 1000);        values.put(MediaStore.Video.Media.DURATION, duration);        //注意:MediaStore.Images.Media.RELATIVE_PATH需要targetSdkVersion=29,        //故该方法只可在Android10的手机上执行        values.put(MediaStore.Video.Media.RELATIVE_PATH, relativePath);        //EXTERNAL_CONTENT_URI代表外部存储器        Uri external = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;        //insertUri表示文件保存的uri路径        Uri insertUri = resolver.insert(external, values);        return String.valueOf(insertUri);    }    /**     * Delete video record by android_Q api     * AndroidQ以上删除视频记录     *     * @param context 上下文,the context     * @param uri     文件的uri the uri of file     * @return 删除的数量,如果是0,代表删除失败 The number of deletions. If it is 0, it means the deletion failed     */    public static int deleteVideoRecord_Q(Context context, Uri uri) {        context = context.getApplicationContext();        ContentResolver contentResolver = context.getContentResolver();        if (contentResolver == null) {            return 0;        }        Cursor cursor = null;        String column = MediaStore.MediaColumns._ID;        int fileID = -1;        try {            cursor = contentResolver.query(uri, new String[]{column}, null, null,                    null);            if (cursor != null && cursor.moveToFirst()) {                int column_index = cursor.getColumnIndexOrThrow(column);                fileID = cursor.getInt(column_index);            }        } catch (Exception e) {            LogUtils.e(e);        } finally {            if (cursor != null) {                cursor.close();            }        }        if (fileID >= 0) {            return contentResolver.delete(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, column + "=?", new String[]{String.valueOf(fileID)});        }        return 0;    }    /**     * 获取媒体数据列表     * Gets a list of media data     *     * @param type TYPE_VIDEO = 0; 视频 TYPE_PHOTO = 1;图片;YPE_ALL = 2;图片和视频     */    public static void getMediaList(final int type, final String[] filter, final MediaCallback callback, int mCurrentPage) {        ThreadUtils.getCachedPool().execute(new Runnable() {            @Override            public void run() {                final List dataList = new ArrayList();                if (type == MediaData.TYPE_ALL) {                    Cursor cursor = getMediaCursor(MediaData.TYPE_PHOTO, mCurrentPage);                    if (cursor != null) {                        createMediaData(cursor, filter, dataList, false);                        cursor.close();                    }                    cursor = getMediaCursor(MediaData.TYPE_VIDEO, mCurrentPage);                    if (cursor != null) {                        createMediaData(cursor, filter, dataList, true);                        cursor.close();                    }                } else {                    Cursor cursor = getMediaCursor(type, mCurrentPage);                    if (cursor != null) {                        createMediaData(cursor,filter, dataList, type == MediaData.TYPE_VIDEO);                        cursor.close();                    }                }                if (callback != null) {                    ThreadUtils.runOnUiThread(new Runnable() {                        @Override                        public void run() {                            callback.onResult(dataList);                        }                    });                }            }        });    }    @SuppressLint("InlinedApi")    private static Cursor getMediaCursor(int type, int mCurrentPage) {        String[] projection = null;        Uri uri = null;        String order = null;        if (type == MediaData.TYPE_VIDEO) {            projection = new String[]{MediaStore.Video.Thumbnails._ID                    , MediaStore.Video.Media._ID                    , MediaStore.Video.Thumbnails.DATA                    , MediaStore.Video.Media.DURATION                    , MediaStore.Video.Media.SIZE                    , MediaStore.Video.Media.DATE_ADDED                    , MediaStore.Video.Media.DISPLAY_NAME                    , MediaStore.Video.Media.DATE_MODIFIED};            uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;            order = MediaStore.Video.Media.DATE_ADDED;        } else if (type == MediaData.TYPE_PHOTO) {            projection = new String[]{                    MediaStore.Images.Media._ID,                    MediaStore.Images.Media.DATA,                    MediaStore.Images.Media.DATE_ADDED,                    MediaStore.Images.Thumbnails.DATA,                    MediaStore.MediaColumns.DISPLAY_NAME            };            uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;            order = MediaStore.Images.Media.DATE_ADDED;        }        if (projection == null) {            return null;        }        // 兼容折叠屏,在Android R及以上手机,order中禁止了LIMIT关键字,所以在这里做了适配        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {            Bundle bundle = new Bundle();            bundle.putInt(ContentResolver.QUERY_ARG_OFFSET, mCurrentPage * PAGE_SIZE);            bundle.putInt(ContentResolver.QUERY_ARG_LIMIT, PAGE_SIZE);            bundle.putStringArray(ContentResolver.QUERY_ARG_SORT_COLUMNS, new String[]{order + " DESC"});            return Utils.getApp().getContentResolver().query(uri, projection, bundle, null);        } else {            String sortOrder = order + " DESC LIMIT " + PAGE_SIZE + " OFFSET " + mCurrentPage * PAGE_SIZE;            return Utils.getApp().getContentResolver().query(uri, projection, null, null, sortOrder);        }    }    /**     * 创建媒体实体类并添加到集合中     * Create a media entity class and add it to the collection     */    @SuppressLint("InlinedApi")    private static void createMediaData(Cursor cursor, String[] filter, List list, boolean isVideo) {        if (cursor != null) {            String mediaId;            String mediaDate;            String mediaThumbnails;            String mediaDisplayName;            if (isVideo) {                mediaId = MediaStore.Video.Media._ID;                mediaDate = MediaStore.Video.Media.DATE_ADDED;                mediaThumbnails = MediaStore.Video.Thumbnails.DATA;                mediaDisplayName = MediaStore.Video.Media.DISPLAY_NAME;            } else {                mediaId = MediaStore.Images.Media._ID;                mediaDate = MediaStore.Images.Media.DATE_ADDED;                mediaThumbnails = MediaStore.Images.Thumbnails.DATA;                mediaDisplayName = MediaStore.Images.Media.DISPLAY_NAME;            }            while (cursor.moveToNext()) {                int videoId = cursor.getInt(cursor.getColumnIndex(mediaId));                String absolutePath = cursor.getString(cursor.getColumnIndex(mediaThumbnails));                String path = AndroidVersionUtils.isAboveAndroid_Q()? AndroidVersionUtils.getRealPathAndroid_Q(Uri.parse(absolutePath)): absolutePath;                String displayName = cursor.getString(cursor.getColumnIndex(mediaDisplayName));                int timeIndex = cursor.getColumnIndex(mediaDate);                long date = cursor.getLong(timeIndex) * 1000;                if (fileIsValid(path)) {                    if (!TextUtils.isEmpty(absolutePath)) {                        int lastDot = absolutePath.lastIndexOf(".");                        String type = absolutePath.substring(lastDot + 1);                        if (!TextUtils.isEmpty(type)) {                            type = type.toLowerCase();                            if (type.equals("mpg") || type.equals("mkv")) {                                continue;                            }                            //过滤文件类型                            boolean isFilter = false;                            if (filter != null && filter.length > 0) {                                for (int i = 0; i                                                 

上一篇:uart串口环回(加FIFO)

下一篇:Java投票系统源码深度解析,构建高效安全的在线投票平台