我使用@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倍,棒极了。

07-28 11:47