Android读取本地照片和视频相册实例代码

发布时间 - 2026-01-11 01:44:54    点击率:

前言

项目中经常要选择本地照片或者视频的需求,如果去扫描整个SD卡就太耗时间,其实Android系统在启动时就已经把整个设备中的多媒体文件信息(文件名,类型,大小等)都存到了数据库,然后提供了ContentPrivider这个API来管理这个数据库,我们可以利用ContentPrivider来获取所有的照片和视频。

ContentPrivider初识

先看下管理的的数据库在哪

data/data/目录下:有很多这种文件夹(日历,联系人,下载管理,多媒体等)


我们需要的照片和视频就在media下面,进去看看。进去找到database然后打开external.db,就可以看到多张表(音频,文件,Log,图像,视频等)

照片相册

那么获取照片直接通过 ContentProvider读取Images这个数据库就OK了,这里开启工作线程读取所有.jpeg和.png的图片,附上代码段:

 /**
  * 读取手机中所有图片信息
  */
 private void getAllPhotoInfo() {
  new Thread(new Runnable() {
   @Override
   public void run() {
    List<MediaBean> mediaBeen = new ArrayList<>();
    HashMap<String,List<MediaBean>> allPhotosTemp = new HashMap<>();//所有照片
    Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
    String[] projImage = { MediaStore.Images.Media._ID
      , MediaStore.Images.Media.DATA
      ,MediaStore.Images.Media.SIZE
      ,MediaStore.Images.Media.DISPLAY_NAME};
    Cursor mCursor = getContentResolver().query(mImageUri,
      projImage,
      MediaStore.Images.Media.MIME_TYPE + "=? or " + MediaStore.Images.Media.MIME_TYPE + "=?",
      new String[]{"image/jpeg", "image/png"},
      MediaStore.Images.Media.DATE_MODIFIED+" desc");

    if(mCursor!=null){
     while (mCursor.moveToNext()) {
      // 获取图片的路径
      String path = mCursor.getString(mCursor.getColumnIndex(MediaStore.Images.Media.DATA));
      int size = mCursor.getInt(mCursor.getColumnIndex(MediaStore.Images.Media.SIZE))/1024;
      String displayName = mCursor.getString(mCursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME));
      //用于展示相册初始化界面
      mediaBeen.add(new MediaBean(MediaBean.Type.Image,path,size,displayName));
      // 获取该图片的父路径名
      String dirPath = new File(path).getParentFile().getAbsolutePath();
      //存储对应关系
      if (allPhotosTemp.containsKey(dirPath)) {
       List<MediaBean> data = allPhotosTemp.get(dirPath);
       data.add(new MediaBean(MediaBean.Type.Image,path,size,displayName));
       continue;
      } else {
       List<MediaBean> data = new ArrayList<>();
       data.add(new MediaBean(MediaBean.Type.Image,path,size,displayName));
       allPhotosTemp.put(dirPath,data);
      }
     }
     mCursor.close();
    }
    //更新界面
    runOnUiThread(new Runnable() {
     @Override
     public void run() {
      //...
     }
    });
   }
  }).start();
 }

有四点需要注意:

  1. MediaBean是文件实体类,代码就不贴了
  2. 照片集合不是放在List<MediaBean>这样存储的,而是HashMap<String,List<MediaBean>>,这样把图片已文件夹(也就是父目录)分类,更节省内存,其次支持相册展示不同文件夹的照片
  3. 貌似没办法获取当前设备的拍照默认路径,有的设备是/DCIM,有的是/100andro还有/camera,那相册就默认展示最近所有照片吧。然后给用户列出一个文件夹列表让他选,这时可以把这几个文件夹放到最前面展示,算是小优化吧。
  4. 系统会时刻检测数据变化,有新的照片这个数据库会自动更新,不需干预。

视频相册

获取视频文件和上面基本一样,不过改下查询条件就行了,实际中有个问题:视频封面的获取。

首先视频封面缩略图在这个videothumbnails数据库,照片缩略图在thumbnails,对应到本地SD卡就是在sdcard/DCIM/.thumbnails/文件夹(有的设备可能不同)

PS:这个文件夹是隐藏的,so你知道你的手机为何存储空间越来越小了吧,拍的照片缩略图全在这儿。。。非常非常多


实际中发现读取不到新录制的视频封面,需要手动调用一个方法,来生成这个封面然后才能在videothumbnails读取到:

参考:http://stackoverflow.com/questions/27903264/how-to-get-the-video-thumbnail-path-and-not-the-bitmap

//videoId是这个视频文件在数据库的ID
MediaStore.Video.Thumbnails.getThumbnail(getContentResolver(), videoId, MediaStore.Video.Thumbnails.MICRO_KIND, null);

并且这里封面和视频不在一个数据库,需要在两个cursor来读取

我这里获取整个SD的mp4格式视频,代码段如下:

 /**
  * 获取手机中所有视频的信息
  */
 private void getAllVideoInfos(){
  new Thread(new Runnable() {
   @Override
   public void run() {
    HashMap<String,List<MediaBean>> allPhotosTemp = new HashMap<>();//所有照片
    Uri mImageUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
    String[] proj = { MediaStore.Video.Thumbnails._ID
      , MediaStore.Video.Thumbnails.DATA
      ,MediaStore.Video.Media.DURATION
      ,MediaStore.Video.Media.SIZE
      ,MediaStore.Video.Media.DISPLAY_NAME
      ,MediaStore.Video.Media.DATE_MODIFIED};
    Cursor mCursor = getContentResolver().query(mImageUri,
      proj,
      MediaStore.Video.Media.MIME_TYPE + "=?",
      new String[]{"video/mp4"},
      MediaStore.Video.Media.DATE_MODIFIED+" desc");
    if(mCursor!=null){
     while (mCursor.moveToNext()) {
      // 获取视频的路径
      int videoId = mCursor.getInt(mCursor.getColumnIndex(MediaStore.Video.Media._ID));
      String path = mCursor.getString(mCursor.getColumnIndex(MediaStore.Video.Media.DATA));
      int duration = mCursor.getInt(mCursor.getColumnIndex(MediaStore.Video.Media.DURATION));
      long size = mCursor.getLong(mCursor.getColumnIndex(MediaStore.Video.Media.SIZE))/1024; //单位kb
      if(size<0){
       //某些设备获取size<0,直接计算
       Log.e("dml","this video size < 0 " + path);
       size = new File(path).length()/1024;
      }
      String displayName = mCursor.getString(mCursor.getColumnIndex(MediaStore.Video.Media.DISPLAY_NAME));
      long modifyTime = mCursor.getLong(mCursor.getColumnIndex(MediaStore.Video.Media.DATE_MODIFIED));//暂未用到

      //提前生成缩略图,再获取:http://stackoverflow.com/questions/27903264/how-to-get-the-video-thumbnail-path-and-not-the-bitmap
      MediaStore.Video.Thumbnails.getThumbnail(getContentResolver(), videoId, MediaStore.Video.Thumbnails.MICRO_KIND, null);
      String[] projection = { MediaStore.Video.Thumbnails._ID, MediaStore.Video.Thumbnails.DATA};
      Cursor cursor = getContentResolver().query(MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI
        , projection
        , MediaStore.Video.Thumbnails.VIDEO_ID + "=?"
        , new String[]{videoId+""}
        , null);
      String thumbPath = "";
      while (cursor.moveToNext()){
       thumbPath = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Thumbnails.DATA));
      }
      cursor.close();
      // 获取该视频的父路径名
      String dirPath = new File(path).getParentFile().getAbsolutePath();
      //存储对应关系
      if (allPhotosTemp.containsKey(dirPath)) {
       List<MediaBean> data = allPhotosTemp.get(dirPath);
       data.add(new MediaBean(MediaBean.Type.Video,path,thumbPath,duration,size,displayName));
       continue;
      } else {
       List<MediaBean> data = new ArrayList<>();
       data.add(new MediaBean(MediaBean.Type.Video,path,thumbPath,duration,size,displayName));
       allPhotosTemp.put(dirPath,data);
      }
     }
     mCursor.close();
    }
    //更新界面
    runOnUiThread(new Runnable() {
     @Override
     public void run() {
      //...
     }
    });
   }
  }).start();
 }

后记

其实Android已经提供叫做CursorLoader的API做这个事情,不需要手动new 工作线程,使用起来很简单有需要可以对上面代码改造。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# android  # 读取相册照片  # 读取本地相册  # Android读取本地照片  # Android使用phonegap从相册里面获取照片(代码分享)  # 基于Android实现保存图片到本地并可以在相册中显示出来  # Android拍照保存在系统相册不显示的问题解决方法  # android照相、相册获取图片剪裁报错的解决方法  # Android实现读取相机(相册)图片并进行剪裁  # Android实现调用系统相册和拍照的Demo示例  # Android开发从相机或相册获取图片裁剪  # Android拍照和获取相册图片  # Android打开相机和相册实例代码  # Android实现保存图片到本地并在相册中显示  # 视频文件  # 机中  # 放在  # 就在  # 有个  # 在这个  # 让他  # 有很多  # 不需要  # 就不  # 你知道  # 能在  # 没办法  # 很简单  # 时就  # 不需  # 在这儿  # 这几个  # 可以利用  # 以对 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 网站制作大概多少钱一个,做一个平台网站大概多少钱?  JavaScript实现Fly Bird小游戏  Win10如何卸载预装Edge扩展_Win10卸载Edge扩展教程【方法】  HTML5建模怎么导出为FBX格式_FBX格式兼容性及导出步骤【指南】  Laravel Fortify是什么,和Jetstream有什么关系  如何用美橙互联一键搭建多站合一网站?  phpredis提高消息队列的实时性方法(推荐)  Python并发异常传播_错误处理解析【教程】  高端云建站费用究竟需要多少预算?  如何快速启动建站代理加盟业务?  微信推文制作网站有哪些,怎么做微信推文,急?  php在windows下怎么调试_phpwindows环境调试操作说明【操作】  Laravel Asset编译怎么配置_Laravel Vite前端构建工具使用  利用 Google AI 进行 YouTube 视频 SEO 描述优化  Laravel如何实现API版本控制_Laravel版本化API设计方案  如何登录建站主机?访问步骤全解析  北京的网站制作公司有哪些,哪个视频网站最好?  如何彻底卸载建站之星软件?  Linux系统运维自动化项目教程_Ansible批量管理实战  CSS3怎么给轮播图加过渡动画_transition加transform实现【技巧】  Laravel如何发送系统通知?(Notification渠道示例)  手机软键盘弹出时影响布局的解决方法  javascript中数组(Array)对象和字符串(String)对象的常用方法总结  html5的keygen标签为什么废弃_替代方案说明【解答】  大连网站制作公司哪家好一点,大连买房网站哪个好?  C++用Dijkstra(迪杰斯特拉)算法求最短路径  Laravel如何实现多级无限分类_Laravel递归模型关联与树状数据输出【方法】  JS中页面与页面之间超链接跳转中文乱码问题的解决办法  Laravel怎么实现前端Toast弹窗提示_Laravel Session闪存数据Flash传递给前端【方法】  Win11搜索栏无法输入_解决Win11开始菜单搜索没反应问题【技巧】  长沙做网站要多少钱,长沙国安网络怎么样?  如何用5美元大硬盘VPS安全高效搭建个人网站?  公司网站制作需要多少钱,找人做公司网站需要多少钱?  canvas 画布在主流浏览器中的尺寸限制详细介绍  Laravel如何实现图片防盗链功能_Laravel中间件验证Referer来源请求【方案】  Laravel如何处理文件上传_Laravel Storage门面实现文件存储与管理  Java遍历集合的三种方式  jimdo怎样用html5做选项卡_jimdo选项卡html5实现与切换效果【指南】  Laravel如何为API生成Swagger或OpenAPI文档  google浏览器怎么清理缓存_谷歌浏览器清除缓存加速详细步骤  如何在阿里云购买域名并搭建网站?  油猴 教程,油猴搜脚本为什么会网页无法显示?  Laravel如何优化应用性能?(缓存和优化命令)  JS去除重复并统计数量的实现方法  laravel怎么用DB facade执行原生SQL查询_laravel DB facade原生SQL执行方法  Laravel如何将应用部署到生产服务器_Laravel生产环境部署流程  Laravel怎么配置不同环境的数据库_Laravel本地测试与生产环境动态切换【方法】  详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)  Laravel如何与Docker(Sail)协同开发?(环境搭建教程)  C#如何调用原生C++ COM对象详解