1. overview
All file paths in the Andorid system are saved in a database, which is located in external.db under the folder data/data/com.android.providers.media
The files table inside has what we need. This table contains all the files of the machine. Next, just select the appropriate sql statement to get what we need.
2. implementation
The database structure is as follows
First filter out the album folder, get the folder path, folder name, number of folder files, file path and modification time. Build folders and covers
public static Cursor getAlbumCursor(ContentResolver cr){ //Open the files table 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 + ")" }; //Consolidate with 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+"",//Get picture file MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO+"",//Get video file }; String sortOrder = MediaStore.Images.Media.DATE_MODIFIED + " desc"; // String sortOrder = "max(date_modified) DESC"; // Convert to sql statement: select parent, bucket display name, count (*), u 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); }
After getting cursor, you can query and get data
public Album(Cursor cur) { //Picture path this(cur.getString(3), //Name of the folder cur.getString(1), //Parent file cur.getLong(0), //Number of files in the folder cur.getInt(2), //Modification time cur.getLong(4) ); }
After the album folder is built, you can get all the pictures in the folder
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 }; //Get the same file as 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); }
Next, build the entity class
public Media(Cursor cur) { //Specific path this(cur.getString(0), cur.getLong(1), cur.getString(2), cur.getLong(3), cur.getInt(4)); }
This way is mainly to use the sql statement, combined with rxjava, you can query a photo and display a photo.
3. expansion
Similarly, you can get specific types of files
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; }