前言

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

ContentPrivider初识

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

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

image.png

我们需要的照片和视频就在media下面,进去看看

进去找到database然后打开external.db,就可以看到多张表(音频,文件,Log,图像,视频等)

image.png

照片相册

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

/**

* 读取手机中所有图片信息

*/

private void getAllPhotoInfo() {

new Thread(new Runnable() {

@Override

public void run() {

List mediaBeen = new ArrayList<>();

HashMap> 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 data = allPhotosTemp.get(dirPath);

data.add(new MediaBean(MediaBean.Type.Image,path,size,displayName));

continue;

} else {

List 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这样存储的,而是HashMap>,这样把图片已文件夹(也就是父目录)分类,更节省内存,其次支持相册展示不同文件夹的照片

貌似没办法获取当前设备的拍照默认路径,有的设备是/DCIM,有的是/100andro还有/camera,那相册就默认展示最近所有照片吧。然后给用户列出一个文件夹列表让他选,这时可以把这几个文件夹放到最前面展示,算是小优化吧。

系统会时刻检测数据变化,有新的照片这个数据库会自动更新,不需干预。

看下相册效果

image.png

视频相册

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

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

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

image.png

//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> 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 data = allPhotosTemp.get(dirPath);

data.add(new MediaBean(MediaBean.Type.Video,path,thumbPath,duration,size,displayName));

continue;

} else {

List 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 工作线程,使用起来很简单有需要可以对上面代码改造。

image.png

android 图片读写,Android读取本地照片和视频相册相关推荐

  1. android 图片读写,Android系统中图片的读写

    读取手机图片: Bitmap bmp=BitmapFactroy.decodeFile("/sdcard/xxx.png"); imageview.setImageBitmap(b ...

  2. android 图片变量,Android开发实现ImageView加载摄像头拍摄的大图功能

    本文实例讲述了Android开发实现ImageView加载摄像头拍摄的大图功能.分享给大家供大家参考,具体如下: 这个方法是从官方demo中摘录的,在此记录学习. 权限 android:name=&q ...

  3. android 图片分析,Android图片处理实例分析

    本文实例讲述了Android图片处理的方法.分享给大家供大家参考,具体如下: package cn.szbw.util; import Android.content.Context; import ...

  4. android 图片拍照,Android获取图片拍照时间

    为什么写这篇文章是因为今早有个需求需要获取图片拍照时的时间进行一些处理,有些方法参数名忘记了,所以谷歌百度了一下,Android 图片 时间,Android 图片 拍照 时间,这几个关键字居然无法搜索 ...

  5. android 图片列表,Android 列表使用(ListView GridView Gallery图片计时滚动)

    ListView 作用: 1.将数据填充到布局. 2.处理用户的选择点击等操作. 根据列表的适配器类型,列表分为三种,ArrayAdapter,SimpleAdapter和SimpleCursorAd ...

  6. android 图片气泡,android图片上显示气泡消息

    经常需要在一个图片上面显示一个气泡,在气泡上面显示消息的数量.这里提供一种方法,直接设置textview的背景色,并且设置textview的文本信息. xmlns:tools="http:/ ...

  7. Android图片褪色,Android – 使用Alpha褪色动画闪烁图片

    我一直在努力了几天,在这一切,终于刚决定问.它很简单我必须缺少一些非常基本的东西. 我有一个XML布局页面定义了一个图像.我有两个anim XML页面,一个将alpha从0更改为1,另一个从1更改为0 ...

  8. android 图片 切换,Android 应用开发笔记 - 切换图片(ImageSwitcher)

    在面板拖拽图标,然后更改相关属性(Properties),如下: android:id="@+id/imgSwit01" android:layout_width="wr ...

  9. android 图片淡入,Android使用ImageView淡入和淡出

    要实现这一点,你已经开始,你将需要添加一个 AnimationListener,以便您可以检测动画的开始和结束.当调用淡出的onAnimationEnd()时,您可以将ImageView对象的可见性设 ...

最新文章

  1. Linux教程 网络管理命令Netstat的使用
  2. Verilog初级教程(20)Verilog中的`ifdef 条件编译语句
  3. Win7上防火墙开放FTP服务以及ping解决方案
  4. POI Excel表格合并,边框设置
  5. Java基础知识强化之IO流笔记13:递归之不死神兔问题(斐波那契数列)
  6. 【POJ - 3744】Scout YYF I(概率dp,矩阵快速幂优化dp)
  7. 中移动飞信2010Beta1.0体验版
  8. ncre二级java_如何备考计算机二级java?
  9. 【mysql基础知识】解决java连接mysql时将localhost改为本机的ip地址后失败问题
  10. Oracle典型应用场景--数据迁移到本地测试
  11. 怎样才能减少汽车油耗呢?
  12. 农村新农保加钱可不可以转城市社保?
  13. IDEA配置openCV
  14. CAD图纸转换成高质量的彩色PDF格式如何操作?
  15. 死区4个状态分析,以及死区时间计算
  16. 关于“#define REG_MEM_BASE (*(volatile unsigend long *)(PA_BAES + 0x00000050))”语句的解析
  17. 安装CentOS7出现dracut-initqueue timeout的解决办法
  18. RESTful风格API详解
  19. IND-CPA(选择明文攻击下的不可区分性)
  20. 【PyTorch系例】torch.Tensor详解和常用操作

热门文章

  1. Python函数设计与使用
  2. python的pyaudio教程入门_Python PyAudio 安装使用
  3. idea java svn 设置_idea配置svn,随时拉取和上传代码的正确做法
  4. L1、L2正则化总结
  5. 《通信原理》(2):信息量及平均信息量
  6. php 的单例模式(二)
  7. 服务器系统解决方案,服务器操作系统解决方案
  8. docker GitLab-runner CI/CD持续集成
  9. Asible简介及部署
  10. 站长得知道的九种工具