Android读取本地照片和视频相册实例代码
前言
项目中经常要选择本地照片或者视频的需求,如果去扫描整个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(); }
有四点需要注意:
- mediabean是文件实体类,代码就不贴了
- 照片集合不是放在list<mediabean>这样存储的,而是hashmap<string,list<mediabean>>,这样把图片已文件夹(也就是父目录)分类,更节省内存,其次支持相册展示不同文件夹的照片
- 貌似没办法获取当前设备的拍照默认路径,有的设备是/dcim,有的是/100andro还有/camera,那相册就默认展示最近所有照片吧。然后给用户列出一个文件夹列表让他选,这时可以把这几个文件夹放到最前面展示,算是小优化吧。
- 系统会时刻检测数据变化,有新的照片这个数据库会自动更新,不需干预。
视频相册
获取视频文件和上面基本一样,不过改下查询条件就行了,实际中有个问题:视频封面的获取。
首先视频封面缩略图在这个videothumbnails数据库,照片缩略图在thumbnails,对应到本地sd卡就是在sdcard/dcim/.thumbnails/文件夹(有的设备可能不同)
ps:这个文件夹是隐藏的,so你知道你的手机为何存储空间越来越小了吧,拍的照片缩略图全在这儿。。。非常非常多
实际中发现读取不到新录制的视频封面,需要手动调用一个方法,来生成这个封面然后才能在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 工作线程,使用起来很简单有需要可以对上面代码改造。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。