1.概述
在Andorid系统中所有的文件路径都保存在一个数据库中,位于data/data/com.android.providers.media文件夹下的external.db
里面的files表就有我们需要的内容,这个表包含了机器所有的文件。接下来只要选择合适的sql语句来获取我们需要的内容就行了。
2.实现
数据库结构如下图
首先过滤出相册文件夹,获取所在文件夹路径,文件夹名称,文件夹文件数目,文件路径和修改时间。构建文件夹和封面
public static Cursor getAlbumCursor(ContentResolver cr){
//打开files这个表
Uri uri= MediaStore.Files.getContentUri("external");
String [] project =new String[]{
MediaStore.Files.FileColumns.PARENT,
MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
"count(*)",
MediaStore.Images.Media.DATA,
"max(" + MediaStore.Images.Media.DATE_MODIFIED + ")"
};
//用group by进行整合
String selection = String.format("%s=? or %s=?) group by (%s",
MediaStore.Files.FileColumns.MEDIA_TYPE,
MediaStore.Files.FileColumns.MEDIA_TYPE,
MediaStore.Files.FileColumns.PARENT
) ;
String[] selectionArgs = new String[]{
MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE+"",//获取图片文件
MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO+"",//获取视频文件
};
String sortOrder = MediaStore.Images.Media.DATE_MODIFIED + " desc";
// String sortOrder = "max(date_modified) DESC";
// 转换成sql语句: SELECT parent, bucket_display_name, count(*), _data, max(date_modified) FROM files WHERE (media_type=? or media_type=?)
// group by (parent) HAVING (_data NOT LIKE ? ) ORDER BY max(date_modified) DESC
return cr.query(uri,project,selection,selectionArgs,sortOrder);
}
拿到cursor后就可以进行查询获取数据
public Album(Cursor cur) {
//图片路径
this(cur.getString(3),
//所在文件夹的名称
cur.getString(1),
//所在的父文件
cur.getLong(0),
//文件夹的文件数目
cur.getInt(2),
//修改时间
cur.getLong(4)
);
}
相册文件夹构建好了后,在来获取文件夹里面的所有的图片
public static Cursor getMediaCursor(ContentResolver cr,Album album){
Uri uri = MediaStore.Files.getContentUri("external");
String[] sProjection = new String[] {
MediaStore.Images.Media.DATA,
MediaStore.Images.Media.DATE_TAKEN,
MediaStore.Images.Media.MIME_TYPE,
MediaStore.Images.Media.SIZE,
MediaStore.Images.Media.ORIENTATION
};
//获取parent一样的文件
String selections = (String.format("(%s=? or %s=?) and %s=?",
MediaStore.Files.FileColumns.MEDIA_TYPE,
MediaStore.Files.FileColumns.MEDIA_TYPE,
MediaStore.Files.FileColumns.PARENT));
String[] selectionArgs = new String[]{
MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE+"",
MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO+"",
album.getId()+""
};
String sortOrder = MediaStore.Images.Media.DATE_MODIFIED + " desc";
return cr.query(uri,sProjection,selections,selectionArgs,sortOrder);
}
接下来构建实体类
public Media(Cursor cur) {
//具体路径
this(cur.getString(0),
cur.getLong(1),
cur.getString(2),
cur.getLong(3),
cur.getInt(4));
}
这种方式主要是利用好了sql语句,同时结合rxjava的话可以实现查询一张照片显示一张照片的效果。
3.扩展
类似的还可以获取特定类型的文件
private ArrayList<LayoutElementParcelable> listImages() {
ArrayList<LayoutElementParcelable> images = new ArrayList<>();
final String[] projection = {MediaStore.Images.Media.DATA};
final Cursor cursor = c.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection, null, null, null);
if (cursor == null)
return images;
else if (cursor.getCount() > 0 && cursor.moveToFirst()) {
do {
String path = cursor.getString(cursor.getColumnIndex
(MediaStore.Files.FileColumns.DATA));
HybridFileParcelable strings = RootHelper.generateBaseFile(new File(path), showHiddenFiles);
if (strings != null) {
LayoutElementParcelable parcelable = createListParcelables(strings);
if(parcelable != null) images.add(parcelable);
}
} while (cursor.moveToNext());
}
cursor.close();
return images;
}
private ArrayList<LayoutElementParcelable> listVideos() {
ArrayList<LayoutElementParcelable> videos = new ArrayList<>();
final String[] projection = {MediaStore.Images.Media.DATA};
final Cursor cursor = c.getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
projection, null, null, null);
if (cursor == null)
return videos;
else if (cursor.getCount() > 0 && cursor.moveToFirst()) {
do {
String path = cursor.getString(cursor.getColumnIndex
(MediaStore.Files.FileColumns.DATA));
HybridFileParcelable strings = RootHelper.generateBaseFile(new File(path), showHiddenFiles);
if (strings != null) {
LayoutElementParcelable parcelable = createListParcelables(strings);
if(parcelable != null) videos.add(parcelable);
}
} while (cursor.moveToNext());
}
cursor.close();
return videos;
}
private ArrayList<LayoutElementParcelable> listaudio() {
String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0";
String[] projection = {
MediaStore.Audio.Media.DATA
};
Cursor cursor = c.getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
null,
null);
ArrayList<LayoutElementParcelable> songs = new ArrayList<>();
if (cursor == null)
return songs;
else if (cursor.getCount() > 0 && cursor.moveToFirst()) {
do {
String path = cursor.getString(cursor.getColumnIndex
(MediaStore.Files.FileColumns.DATA));
HybridFileParcelable strings = RootHelper.generateBaseFile(new File(path), showHiddenFiles);
if (strings != null) {
LayoutElementParcelable parcelable = createListParcelables(strings);
if(parcelable != null) songs.add(parcelable);
}
} while (cursor.moveToNext());
}
cursor.close();
return songs;
}
private ArrayList<LayoutElementParcelable> listDocs() {
ArrayList<LayoutElementParcelable> docs = new ArrayList<>();
final String[] projection = {MediaStore.Files.FileColumns.DATA};
Cursor cursor = c.getContentResolver().query(MediaStore.Files.getContentUri("external"),
projection, null, null, null);
String[] types = new String[]{".pdf", ".xml", ".html", ".asm", ".text/x-asm", ".def", ".in", ".rc",
".list", ".log", ".pl", ".prop", ".properties", ".rc",
".doc", ".docx", ".msg", ".odt", ".pages", ".rtf", ".txt", ".wpd", ".wps"};
if (cursor == null)
return docs;
else if (cursor.getCount() > 0 && cursor.moveToFirst()) {
do {
String path = cursor.getString(cursor.getColumnIndex
(MediaStore.Files.FileColumns.DATA));
if (path != null && Arrays.asList(types).contains(path)) {
HybridFileParcelable strings = RootHelper.generateBaseFile(new File(path), showHiddenFiles);
if (strings != null) {
LayoutElementParcelable parcelable = createListParcelables(strings);
if(parcelable != null) docs.add(parcelable);
}
}
} while (cursor.moveToNext());
}
cursor.close();
Collections.sort(docs, (lhs, rhs) -> -1 * Long.valueOf(lhs.date).compareTo(rhs.date));
if (docs.size() > 20)
for (int i = docs.size() - 1; i > 20; i--) {
docs.remove(i);
}
return docs;
}
private ArrayList<LayoutElementParcelable> listApks() {
ArrayList<LayoutElementParcelable> apks = new ArrayList<>();
final String[] projection = {MediaStore.Files.FileColumns.DATA};
Cursor cursor = c.getContentResolver()
.query(MediaStore.Files.getContentUri("external"), projection, null, null, null);
if (cursor == null)
return apks;
else if (cursor.getCount() > 0 && cursor.moveToFirst()) {
do {
String path = cursor.getString(cursor.getColumnIndex
(MediaStore.Files.FileColumns.DATA));
if (path != null && path.endsWith(".apk")) {
HybridFileParcelable strings = RootHelper.generateBaseFile(new File(path), showHiddenFiles);
if (strings != null) {
LayoutElementParcelable parcelable = createListParcelables(strings);
if(parcelable != null) apks.add(parcelable);
}
}
} while (cursor.moveToNext());
}
cursor.close();
return apks;
}