欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-11-24 08:31:28
前言 项目中经常要选择本地照片或者视频的需求,如果去扫描整个sd卡就太耗时间,其实android系统在启动时就已经把整个设备中的多媒体文件信息(文件名,类型,大小等)都存...

前言

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

contentprivider初识

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

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

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

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

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

照片相册

那么获取照片直接通过 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你知道你的手机为何存储空间越来越小了吧,拍的照片缩略图全在这儿。。。非常非常多

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

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

参考:

//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://*.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读取本地照片和视频相册实例代码

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