Android讀取本地照片和視頻相冊(cè)實(shí)例代碼
前言
項(xiàng)目中經(jīng)常要選擇本地照片或者視頻的需求,如果去掃描整個(gè)SD卡就太耗時(shí)間,其實(shí)Android系統(tǒng)在啟動(dòng)時(shí)就已經(jīng)把整個(gè)設(shè)備中的多媒體文件信息(文件名,類(lèi)型,大小等)都存到了數(shù)據(jù)庫(kù),然后提供了ContentPrivider這個(gè)API來(lái)管理這個(gè)數(shù)據(jù)庫(kù),我們可以利用ContentPrivider來(lái)獲取所有的照片和視頻。
ContentPrivider初識(shí)
先看下管理的的數(shù)據(jù)庫(kù)在哪
data/data/目錄下:有很多這種文件夾(日歷,聯(lián)系人,下載管理,多媒體等)

我們需要的照片和視頻就在media下面,進(jìn)去看看。進(jìn)去找到database然后打開(kāi)external.db,就可以看到多張表(音頻,文件,Log,圖像,視頻等)

照片相冊(cè)
那么獲取照片直接通過(guò) ContentProvider讀取Images這個(gè)數(shù)據(jù)庫(kù)就OK了,這里開(kāi)啟工作線程讀取所有.jpeg和.png的圖片,附上代碼段:
/**
* 讀取手機(jī)中所有圖片信息
*/
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));
//用于展示相冊(cè)初始化界面
mediaBeen.add(new MediaBean(MediaBean.Type.Image,path,size,displayName));
// 獲取該圖片的父路徑名
String dirPath = new File(path).getParentFile().getAbsolutePath();
//存儲(chǔ)對(duì)應(yīng)關(guān)系
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();
}
有四點(diǎn)需要注意:
- MediaBean是文件實(shí)體類(lèi),代碼就不貼了
- 照片集合不是放在List<MediaBean>這樣存儲(chǔ)的,而是HashMap<String,List<MediaBean>>,這樣把圖片已文件夾(也就是父目錄)分類(lèi),更節(jié)省內(nèi)存,其次支持相冊(cè)展示不同文件夾的照片
- 貌似沒(méi)辦法獲取當(dāng)前設(shè)備的拍照默認(rèn)路徑,有的設(shè)備是/DCIM,有的是/100andro還有/camera,那相冊(cè)就默認(rèn)展示最近所有照片吧。然后給用戶列出一個(gè)文件夾列表讓他選,這時(shí)可以把這幾個(gè)文件夾放到最前面展示,算是小優(yōu)化吧。
- 系統(tǒng)會(huì)時(shí)刻檢測(cè)數(shù)據(jù)變化,有新的照片這個(gè)數(shù)據(jù)庫(kù)會(huì)自動(dòng)更新,不需干預(yù)。
視頻相冊(cè)
獲取視頻文件和上面基本一樣,不過(guò)改下查詢條件就行了,實(shí)際中有個(gè)問(wèn)題:視頻封面的獲取。
首先視頻封面縮略圖在這個(gè)videothumbnails數(shù)據(jù)庫(kù),照片縮略圖在thumbnails,對(duì)應(yīng)到本地SD卡就是在sdcard/DCIM/.thumbnails/文件夾(有的設(shè)備可能不同)
PS:這個(gè)文件夾是隱藏的,so你知道你的手機(jī)為何存儲(chǔ)空間越來(lái)越小了吧,拍的照片縮略圖全在這兒。。。非常非常多

實(shí)際中發(fā)現(xiàn)讀取不到新錄制的視頻封面,需要手動(dòng)調(diào)用一個(gè)方法,來(lái)生成這個(gè)封面然后才能在videothumbnails讀取到:
參考:http://stackoverflow.com/questions/27903264/how-to-get-the-video-thumbnail-path-and-not-the-bitmap
//videoId是這個(gè)視頻文件在數(shù)據(jù)庫(kù)的ID MediaStore.Video.Thumbnails.getThumbnail(getContentResolver(), videoId, MediaStore.Video.Thumbnails.MICRO_KIND, null);
并且這里封面和視頻不在一個(gè)數(shù)據(jù)庫(kù),需要在兩個(gè)cursor來(lái)讀取
我這里獲取整個(gè)SD的mp4格式視頻,代碼段如下:
/**
* 獲取手機(jī)中所有視頻的信息
*/
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){
//某些設(shè)備獲取size<0,直接計(jì)算
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));//暫未用到
//提前生成縮略圖,再獲?。篽ttp://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();
//存儲(chǔ)對(duì)應(yīng)關(guān)系
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();
}
后記
其實(shí)Android已經(jīng)提供叫做CursorLoader的API做這個(gè)事情,不需要手動(dòng)new 工作線程,使用起來(lái)很簡(jiǎn)單有需要可以對(duì)上面代碼改造。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android使用phonegap從相冊(cè)里面獲取照片(代碼分享)
- 基于Android實(shí)現(xiàn)保存圖片到本地并可以在相冊(cè)中顯示出來(lái)
- Android拍照保存在系統(tǒng)相冊(cè)不顯示的問(wèn)題解決方法
- android照相、相冊(cè)獲取圖片剪裁報(bào)錯(cuò)的解決方法
- Android實(shí)現(xiàn)讀取相機(jī)(相冊(cè))圖片并進(jìn)行剪裁
- Android實(shí)現(xiàn)調(diào)用系統(tǒng)相冊(cè)和拍照的Demo示例
- Android開(kāi)發(fā)從相機(jī)或相冊(cè)獲取圖片裁剪
- Android拍照和獲取相冊(cè)圖片
- Android打開(kāi)相機(jī)和相冊(cè)實(shí)例代碼
- Android實(shí)現(xiàn)保存圖片到本地并在相冊(cè)中顯示
相關(guān)文章
刷新Activity中的scrollview示例(局部ui刷新)
代碼很簡(jiǎn)單,但是很實(shí)用,適合在一個(gè)Activity中要刷新局部的UI,比如在掃描一維碼的時(shí)候,要把每次掃描的結(jié)果都顯示在界面上2014-01-01
Android實(shí)現(xiàn)簡(jiǎn)單的分頁(yè)效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡(jiǎn)單的分頁(yè)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11
Android okhttp3.0忽略https證書(shū)的方法
這篇文章主要介紹了 Android okhttp3.0忽略https證書(shū)的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
Android 詳解沉浸式狀態(tài)欄的實(shí)現(xiàn)流程
沉浸式就是要給用戶提供完全沉浸的體驗(yàn),使用戶有一種置身于虛擬世界之中的感覺(jué)。沉浸式模式就是整個(gè)屏幕中顯示都是應(yīng)用的內(nèi)容,沒(méi)有狀態(tài)欄也沒(méi)有導(dǎo)航欄,用戶不會(huì)被一些系統(tǒng)的界面元素所打擾,讓我們來(lái)實(shí)現(xiàn)下網(wǎng)上傳的沸沸揚(yáng)揚(yáng)的安卓沉浸式狀態(tài)欄2021-11-11
Android編程實(shí)現(xiàn)將tab選項(xiàng)卡放在屏幕底部的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)將tab選項(xiàng)卡放在屏幕底部的方法,涉及Android界面布局、tab設(shè)置及權(quán)限控制相關(guān)操作技巧,需要的朋友可以參考下2017-03-03
Android 中基于TabLayout+ViewPager實(shí)現(xiàn)標(biāo)簽卡效果
這篇文章主要介紹了Android 中基于TabLayout+ViewPager實(shí)現(xiàn)標(biāo)簽卡效果,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-12-12
Android中ListView的item點(diǎn)擊沒(méi)有反應(yīng)的解決方法
這篇文章主要介紹了Android中ListView的item點(diǎn)擊沒(méi)有反應(yīng)的相關(guān)資料,需要的朋友可以參考下2017-10-10
Android Service判斷設(shè)備聯(lián)網(wǎng)狀態(tài)詳解
本文主要介紹Android Service判斷聯(lián)網(wǎng)狀態(tài),這里提供了相關(guān)資料并附有示例代碼,有興趣的小伙伴可以參考下,幫助開(kāi)發(fā)相關(guān)應(yīng)用功能2016-08-08

