我使用@pskink解决方案来优化查询代码,通过使用ContentQueryMap
将消耗的时间从3000 + ms减少到200 + ms。
但是我仍然对如何在ContentResolver上实现JOIN
操作感到困惑。根据我的极限经验,我相信使用JOIN
可以将消耗的时间减少到100ms以下。这是我的代码。如何通过ContentResolver实现JOIN
?
顺便说一句,我的代码有优化吗?谢谢!
// scan Music by query table: MediaStore.Audio.AudioColumns .
private void scanMusic() {
Map<String, ContentValues> albumQueryMap = prepareAlbums();
Map<String, ContentValues> artistQueryMap = prepareArtist();
final String[] musicProjection = {
MediaStore.Audio.AudioColumns.DATA,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.ALBUM_ID,
MediaStore.Audio.Media.SIZE,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.DATE_ADDED
};
final String selection = MediaStore.Audio.AudioColumns.IS_MUSIC + " != ? And "
+ MediaStore.Audio.AudioColumns.DURATION + " >= ?";
final String[] selectionArgs = new String[]{"0", "60000"};
Cursor musicCursor = context.getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
musicProjection,
selection,
selectionArgs,
null
);
if (musicCursor != null) {
while (musicCursor.moveToNext()) {
// scan item music
String musicFilePath = musicCursor.getString(0);
String musicName = musicCursor.getString(1);
String musicArtist = musicCursor.getString(2);
String musicAlbumName = musicCursor.getString(3);
String albumId = musicCursor.getString(4);
String coverPath = albumQueryMap.get(albumId).getAsString(MediaStore.Audio.Albums.ALBUM_ART);
String musicFileSize = Formatter.formatFileSize(MainApplication.getBackgroundContext(), musicCursor.getLong(5));
long musicDuration = musicCursor.getLong(6);
long musicAddDate = musicCursor.getLong(7);
Music itemMusic = new Music(musicFilePath, musicName, musicArtist, musicAlbumName, coverPath, musicDuration, musicFileSize, musicAddDate);
mAllMusicList.add(itemMusic);
}
musicCursor.close();
}
}
// scan Albums by query table: MediaStore.Audio.Albums and cache it.
private Map<String, ContentValues> prepareAlbums() {
final String[] projection = {
MediaStore.Audio.Albums._ID,
MediaStore.Audio.Albums.ALBUM,
MediaStore.Audio.Albums.ALBUM_ART,
MediaStore.Audio.Albums.ARTIST,
MediaStore.Audio.Albums.FIRST_YEAR,
MediaStore.Audio.Albums.LAST_YEAR,
MediaStore.Audio.Albums.NUMBER_OF_SONGS,
};
Cursor cursor = MainApplication.getBackgroundContext().getContentResolver().query(
MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
projection,
null,
null,
null);
ContentQueryMap queryMap = new ContentQueryMap(
cursor,
MediaStore.Audio.Albums._ID,
false,
null
);
Map<String, ContentValues> map = queryMap.getRows();
for (String albumId : map.keySet()) {
ContentValues values = map.get(albumId);
String albumName = values.getAsString(MediaStore.Audio.Albums.ALBUM);
String albumArt = values.getAsString(MediaStore.Audio.Albums.ALBUM_ART);
String artist = values.getAsString(MediaStore.Audio.Albums.ARTIST);
String firstYear = values.getAsString(MediaStore.Audio.Albums.FIRST_YEAR);
String lastYear = values.getAsString(MediaStore.Audio.Albums.LAST_YEAR);
int numberOfSongs = values.getAsInteger(MediaStore.Audio.Artists.Albums.NUMBER_OF_SONGS);
Album item = new Album(albumName, albumArt, artist, firstYear, lastYear, numberOfSongs);
mAlbumList.add(item);
}
try {
return map;
} finally {
cursor.close();
queryMap.close();
}
}
// scan Artist by query table:MediaStore.Audio.Artists and cache it.
private Map<String, ContentValues> prepareArtist() {
final String[] projection = {
MediaStore.Audio.Artists._ID,
MediaStore.Audio.Artists.ARTIST,
MediaStore.Audio.Artists.NUMBER_OF_ALBUMS,
MediaStore.Audio.Artists.NUMBER_OF_TRACKS,
};
Cursor cursor = MainApplication.getBackgroundContext().getContentResolver().query(
MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
projection,
null,
null,
null);
ContentQueryMap queryMap = new ContentQueryMap(
cursor,
MediaStore.Audio.Artists._ID,
false,
null
);
Map<String, ContentValues> map = queryMap.getRows();
for (String artistId : map.keySet()) {
ContentValues values = map.get(artistId);
String artist = values.getAsString(MediaStore.Audio.Artists.ARTIST);
int numberOfAlbums = values.getAsInteger(MediaStore.Audio.Artists.NUMBER_OF_ALBUMS);
int numberOfTracks = values.getAsInteger(MediaStore.Audio.Artists.NUMBER_OF_TRACKS);
Artist item = new Artist(artist, numberOfAlbums, numberOfTracks);
mArtistList.add(item);
}
try {
return map;
} finally {
cursor.close();
queryMap.close();
}
}
最佳答案
就像@pskink所说的那样,只需使用ContentQueryMap
来优化查询。为什么ContentQueryMap
可以提高我的查询代码效率吗?
我以前这样写过代码:
private void scanMusic() {
final String[] musicProjection = {
MediaStore.Audio.AudioColumns.DATA,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.ALBUM_ID,
MediaStore.Audio.Media.SIZE,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.DATE_ADDED
};
final String selection = MediaStore.Audio.AudioColumns.IS_MUSIC + " != ? And "
+ MediaStore.Audio.AudioColumns.DURATION + " >= ?";
final String[] selectionArgs = new String[]{"0", "60000"};
Cursor musicCursor = context.getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
musicProjection,
selection,
selectionArgs,
null
);
if (musicCursor != null) {
while (musicCursor.moveToNext()) {
// scan item music
String musicFilePath = musicCursor.getString(0);
String musicName = musicCursor.getString(1);
String musicArtist = musicCursor.getString(2);
String musicAlbumName = musicCursor.getString(3);
String albumId = musicCursor.getString(4);
// Scan the album form once for each row of the music form
String coverPath = getThumbAlbum(albumId);
String musicFileSize = Formatter.formatFileSize(context, musicCursor.getLong(5));
long musicDuration = musicCursor.getLong(6);
long musicAddDate = musicCursor.getLong(7);
Music itemMusic = new Music(musicFilePath, musicName, musicArtist, musicAlbumName, coverPath, musicDuration, musicFileSize, musicAddDate);
mAllMusicList.add(itemMusic);
}
musicCursor.close();
}
}
private String getThumbAlbum(String albumId) {
ContentResolver resolver = context.getContentResolver();
Uri albumUri = MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI;
String id = MediaStore.Audio.Albums._ID;
String[] selection = new String[]{MediaStore.Audio.Albums.ALBUM_ART};
String[] selectionArgs = new String[]{albumId};
Cursor cursor = resolver.query(albumUri, selection, id + "=?", selectionArgs, null);
if (cursor != null && cursor.moveToNext()) {
try {
return cursor.getString(0);
} finally {
cursor.close();
}
}
return null;
}
如何优化我的代码?答案是显而易见的。通过缓存“相册”表单的查询结果,可以减少“相册”表单的查询时间。
通过使用
ContentQueryMap
,我们可以达到预期的结果。我之后写了这样的代码:
private void scanMusic() {
Map<String, ContentValues> albumQueryMap = prepareAlbums();
final String[] musicProjection = {
MediaStore.Audio.AudioColumns.DATA,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.ALBUM_ID,
MediaStore.Audio.Media.SIZE,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.DATE_ADDED
};
final String selection = MediaStore.Audio.AudioColumns.IS_MUSIC + " != ? And "
+ MediaStore.Audio.AudioColumns.DURATION + " >= ?";
final String[] selectionArgs = new String[]{"0", "60000"};
Cursor musicCursor = context.getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
musicProjection,
selection,
selectionArgs,
null
);
if (musicCursor != null) {
while (musicCursor.moveToNext()) {
// scan item music
String musicFilePath = musicCursor.getString(0);
String musicName = musicCursor.getString(1);
String musicArtist = musicCursor.getString(2);
String musicAlbumName = musicCursor.getString(3);
String albumId = musicCursor.getString(4);
String coverPath = albumQueryMap.get(albumId).getAsString(MediaStore.Audio.Albums.ALBUM_ART);
String musicFileSize = Formatter.formatFileSize(context, musicCursor.getLong(5));
long musicDuration = musicCursor.getLong(6);
long musicAddDate = musicCursor.getLong(7);
Music itemMusic = new Music(musicFilePath, musicName, musicArtist, musicAlbumName, coverPath, musicDuration, musicFileSize, musicAddDate);
mAllMusicList.add(itemMusic);
}
musicCursor.close();
}
}
// Caching the query result of Albums form into a Map, with Which we can get coverPath easily by given key.
private Map<String, ContentValues> prepareAlbums() {
final String[] projection = {
MediaStore.Audio.Albums._ID,
MediaStore.Audio.Albums.ALBUM,
MediaStore.Audio.Albums.ALBUM_ART,
MediaStore.Audio.Albums.ARTIST,
MediaStore.Audio.Albums.FIRST_YEAR,
MediaStore.Audio.Albums.LAST_YEAR,
MediaStore.Audio.Albums.NUMBER_OF_SONGS,
};
Cursor cursor = context.getContentResolver().query(
MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
projection,
null,
null,
null
);
ContentQueryMap queryMap = new ContentQueryMap(
cursor,
MediaStore.Audio.Albums._ID,
false,
null
);
try {
return queryMap.getRows();
} finally {
cursor.close();
queryMap.close();
}
}
在使用
ContentQueryMap
之前,该程序在查询时使用3000 + ms,结果大小==273。在使用ContentQueryMap
之后,该程序仅使用200 + ms,速度提高了15倍,棒极了。