MediaData工具类

这个Java代码段展示了如何在Android中处理媒体文件,包括将视频添加到媒体库、删除视频记录、获取媒体数据列表(分页查询视频和图片)以及优化相册加载速度。主要方法如`saveVideo2Album`和`deleteVideoRecord_Q`涉及ContentResolver和MediaStore接口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 添加视频到媒体库
  • 增加视频文件记录、删除视频记录
  • 获取媒体数据列表(分页查询视频列表和图片列表)

优化相册加载速度

package com.meishe.base.utils;

import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;

import com.meishe.base.R;
import com.meishe.base.bean.MediaData;
import com.meishe.base.bean.MediaFolder;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 和媒体相关的工具类
 * Media-related tool classes
 */
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, String photoAlbum) {
        if (Utils.getApp().getResources().getString(R.string.title_Local_album).equals(photoAlbum)) {
            photoAlbum = "";//查本地全部相册
        }
        Log.d("caowj", "获取媒体数据列表:" + photoAlbum);
        String finalPhotoAlbum = photoAlbum;
        ThreadUtils.getCachedPool().execute(new Runnable() {
            @Override
            public void run() {
                final List<MediaData> dataList = new ArrayList<>();
                if (type == MediaData.TYPE_ALL) {
                    Cursor cursor = getMediaCursor(MediaData.TYPE_PHOTO, mCurrentPage, finalPhotoAlbum);
                    if (cursor != null) {
                        createMediaData(cursor, filter, dataList, false);
                        cursor.close();
                    }
                    cursor = getMediaCursor(MediaData.TYPE_VIDEO, mCurrentPage, finalPhotoAlbum);
                    if (cursor != null) {
                        createMediaData(cursor, filter, dataList, true);
                        cursor.close();
                    }
                } else {
                    Cursor cursor = getMediaCursor(type, mCurrentPage, finalPhotoAlbum);
                    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);
                        }
                    });
                }
            }
        });
    }

    /**
     * 获取相册
     *
     * @param callback
     */
    public static void getFolderList(final FolderCallback callback) {
        ThreadUtils.getCachedPool().execute(new Runnable() {
            @Override
            public void run() {
                ArrayList<MediaFolder> folderList = new ArrayList<>();
                Cursor cursor = getFolderCursor();
                MediaFolder allFolder = new MediaFolder(Utils.getApp().getResources().getString(R.string.title_Local_album));
                folderList.add(allFolder);

                while (cursor.moveToNext()) {
                    String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA));
                    String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DISPLAY_NAME));
                    long dateTime = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATE_ADDED));
                    int mediaType = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.MEDIA_TYPE));
                    long size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.SIZE));
                    int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID));

                    if (size < 1) {
                        continue;
                    }
                    if (path == null || "".equals(path)) {
                        continue;
                    }

//            Uri uri = ContentUris.withAppendedId(queryUri, id);
                    String dirName = getParent(path);
                    if (new File(path).exists()) {
                        MediaData mediaData = new MediaData()
                                .setId(id)
                                .setPath(path)
                                .setDate(dateTime)
                                .setDisplayName(name);

                        if (mediaType == MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO) {
                            mediaData.setType(MediaData.TYPE_VIDEO);
                            long duration = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION));
                            mediaData.setDuration((int) duration);
                            if (duration == 0) {
                                mediaData.setDuration(-1);
                            }
                        } else {
                            mediaData.setType(MediaData.TYPE_PHOTO);
                        }

                        if (isGif(path)) {
                            mediaData.setIsGif(true);
                            mediaData.setType(MediaData.TYPE_VIDEO);
                        }

                        allFolder.addMedias(mediaData);
                        int index = hasDir(folderList, dirName);
                        if (index != -1) {
                            folderList.get(index).addMedias(mediaData);
                        } else {
                            MediaFolder folder = new MediaFolder(dirName);
                            folder.addMedias(mediaData);
                            folderList.add(folder);
                        }
                    }
                }

                cursor.close();

                if (callback != null) {
                    ThreadUtils.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Log.d("caowj", "相册数量folders=" + folderList.size());
                            callback.onResult(folderList);
                        }
                    });
                }
            }
        });
    }

    private static String getParent(String path) {
        String[] ss = path.split("/");
        return ss[ss.length - 2];
    }

    private static int hasDir(ArrayList<MediaFolder> folders, String dirName) {
        for (int i = 0; i < folders.size(); i++) {
            MediaFolder folder = folders.get(i);
            if (Objects.equals(folder.name, dirName)) {
                return i;
            }
        }
        return -1;
    }

    @SuppressLint("InlinedApi")
    private static Cursor getMediaCursor(int type, int mCurrentPage, String photoAlbum) {
        String[] projection = null;
        Uri uri = null;
        String order = null;
        String albumName = 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;
            albumName = MediaStore.Video.Media.BUCKET_DISPLAY_NAME;
        } else if (type == MediaData.TYPE_PHOTO) {
            projection = new String[]{
                    MediaStore.Images.Media._ID,
                    MediaStore.Images.Media.DATA,
                    MediaStore.Images.Media.DATE_ADDED,
                    MediaStore.Images.Media.ALBUM,
                    MediaStore.Images.Thumbnails.DATA,
                    MediaStore.MediaColumns.DISPLAY_NAME
            };
            uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            order = MediaStore.Images.Media.DATE_ADDED;
            albumName = MediaStore.Images.Media.BUCKET_DISPLAY_NAME;
        }
        if (projection == null) {
            return null;
        }
        String selection = null;
        String[] selectionArgs = null;
        if (!TextUtils.isEmpty(photoAlbum)) {
            selection = albumName + "=?";//根据相册名称查询
            selectionArgs = new String[]{photoAlbum};
        }

        // 兼容折叠屏,在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);

            if (selection != null) {
                bundle.putString(ContentResolver.QUERY_ARG_SQL_SELECTION, selection);
            }
            if (selectionArgs != null) {
                bundle.putStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS, selectionArgs);
            }
            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, selection, selectionArgs, sortOrder);
        }
    }

    /**
     * 获取相册
     *
     * @return
     */
    private static Cursor getFolderCursor() {
        String[] projection = {
                MediaStore.Files.FileColumns.DATA,
                MediaStore.Files.FileColumns.DISPLAY_NAME,
                MediaStore.Files.FileColumns.DATE_ADDED,
                MediaStore.Files.FileColumns.MEDIA_TYPE,
                MediaStore.Files.FileColumns.SIZE,
                MediaStore.Video.Media.DURATION,
                MediaStore.Files.FileColumns._ID,
                MediaStore.Files.FileColumns.PARENT};

        Uri queryUri = MediaStore.Files.getContentUri("external");

        String selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "="
                + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE
                + " OR "
                + MediaStore.Files.FileColumns.MEDIA_TYPE + "="
                + MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO;

        String sortOrder = MediaStore.Files.FileColumns.DATE_ADDED + " DESC";
        return Utils.getApp().getContentResolver().query(queryUri, projection, selection, null, sortOrder);
    }

    /**
     * 创建媒体实体类并添加到集合中
     * Create a media entity class and add it to the collection
     */
    @SuppressLint("InlinedApi")
    private static void createMediaData(Cursor cursor, String[] filter, List<MediaData> 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.getColumnIndexOrThrow(mediaId));
                String absolutePath = cursor.getString(cursor.getColumnIndexOrThrow(mediaThumbnails));
                String path = AndroidVersionUtils.isAboveAndroid_Q() ? AndroidVersionUtils.getRealPathAndroid_Q(Uri.parse(absolutePath)) : absolutePath;
                String displayName = cursor.getString(cursor.getColumnIndexOrThrow(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 < filter.length; i++) {
                                    String filterItem = filter[i];
                                    if (StringUtils.equals(filterItem, type)) {
                                        isFilter = true;
                                        break;
                                    }
                                }
                            }
                            if (isFilter) {
                                continue;
                            }
                        }
                    }
                    MediaData mediaData = new MediaData()
                            .setId(videoId)
                            .setPath(path)
                            .setDate(date)
                            .setDisplayName(displayName);
                    if (isVideo) {
                        mediaData.setType(MediaData.TYPE_VIDEO)
                                .setDuration(cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION)));
                    } else {
                        mediaData.setType(MediaData.TYPE_PHOTO);
                    }
                    if (isGif(path)) {
                        mediaData.setIsGif(true);
                        mediaData.setType(MediaData.TYPE_VIDEO);
                    }
                    list.add(mediaData);
                }
            }
        }
    }

    /**
     * 判断是否是gif图片
     * Is gif boolean.
     *
     * @param path the path
     * @return the boolean
     */
    public static boolean isGif(String path) {
        String fileName = FileUtils.getFileSuffix(path);
        if (!TextUtils.isEmpty(fileName) && "GIF".equals(fileName.toUpperCase())) {
            return true;
        }
        return false;
    }

    private static boolean fileIsValid(String filePath) {
        if (FileUtils.isAndroidQUriPath(filePath)) {
            return true;
        }
        File file = FileUtils.getFileByPath(filePath);
        return file != null && file.exists();
    }

    public interface MediaCallback {
        void onResult(List<MediaData> dataList);
    }

    public interface FolderCallback {
        void onResult(List<MediaFolder> dataList);
    }
}

获取媒体列表:


    /**
     * 获取媒体列表
     * <p></p>
     * Get media list
     *
     * @param type TYPE_VIDEO = 0; 视频 TYPE_PHOTO = 1;图片;YPE_ALL = 2;图片和视频
     * @param filter  the filter, 过滤文件类型
     * @param mCurrentPage 分页查询的页数
     */
    public void getMediaList(final int type, String[] filter, int mCurrentPage) {
        MediaUtils.getMediaList(type, filter, new MediaUtils.MediaCallback() {
            @Override
            public void onResult(List<MediaData> dataList) {
                if (mCurrentPage == 0) {
                    mDataList = new ArrayList<>();
                }
                mDataList.addAll(dataList);
                if (type == MediaData.TYPE_ALL) {
                    Collections.sort(mDataList, (item1, item2) -> {
                        if (item2.getDate() < item1.getDate()) {
                            return -1;
                        }
                        return (item2.getDate() == item1.getDate() ? 0 : 1);
                    });
                }
                List<MediaSection> list = new ArrayList<>();
                String lastDate = null;
                String date;
                int index = 0;
                for (int i = 0; i < mDataList.size(); i++) {
                    MediaData mediaData = mDataList.get(i);
                    if (mediaData == null) {
                        continue;
                    }
                    date = TimeUtils.millis2String(mediaData.getDate(), "yyyy-MM-dd");
                    if (lastDate == null || !lastDate.equals(date)) {
                        lastDate = date;
                        MediaSection head = new MediaSection(null);
                        head.isHeader = true;
                        head.header = date;
                        index++;
                        list.add(head);
                    }
                    list.add(new MediaSection(mediaData));
                    MediaTag mediaTag = new MediaTag();
                    mediaTag.setIndex(index).setType(type);
                    mediaData.setTag(mediaTag);
                    index++;
                }
                if (getView() != null) {
                    getView().onMediaBack(list);
                }
            }
        }, mCurrentPage);
    }
  MediaUtils.getFolderList { dataList ->
      folderList = dataList
//            filterAdapter.setNewInstance(dataList.toMutableList())
      Log.d("caowj", "相册数量:${dataList?.size}")
  }
   String[] filter = null;
   if (!CommonUtils.isEmpty(mMediaFilter)) {
       filter = new String[mMediaFilter.size()];
       for (int index = 0; index < mMediaFilter.size(); index++) {
           filter[index] = mMediaFilter.get(index);
       }
   }
   mCurrentPage = 0;
   mPresenter.getMediaList(MediaData.TYPE_VIDEO, filter, mCurrentPage);
  // mPresenter.getMediaList(MediaData.TYPE_VIDEO, null, mCurrentPage);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值