在RecyclerView

时间:2015-10-16 00:27:21

标签: android android-asynctask android-cursor android-contentresolver mp3agic

我正在构建一个音乐播放器,它可以从设备上的所有mp3文件中获取BPM ID3v2标签,并允许通过BPM进行排序和过滤。要获取标记,我使用的是mp3agic库。事实证明,这个标签提取需要一些时间用于每首歌曲,并且当将每首歌曲添加到我的歌曲列表中时执行提取会使播放器暂时无功能。我不确定是否应该在完成构建时在整个列表上使用AsyncTask,或者为每个项目使用AsyncTask来检索其BPM并将其插入到歌曲中,或者甚至使用其他更快的获取BPM值的方法。任何人都可以提供任何指导吗?

以下是获取BPM的代码:

public int getBpmFromId(long id) {
    int bpm = -1;
    Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, Long.toString(id));
    try {
        Mp3File file = new Mp3File(getRealPathFromURI(getApplicationContext(), uri));
        if(file.hasId3v2Tag()) {
            ID3v2 id3v2Tag = file.getId3v2Tag();
            bpm = id3v2Tag.getBPM();
            Log.d("MP3AGIC", "Got BPM for track: " + id + ": " + bpm);

        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    return bpm;
}

这是我用来构建歌曲列表的代码:

public void getSongList() {
    ContentResolver musicResolver = getContentResolver();
    Uri musicUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;

    String selectionMimeType = MediaStore.Files.FileColumns.MIME_TYPE + "=?";
    String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0 AND " + selectionMimeType;
    String sortOrder = null;
    String[] projection = null;
    String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension("mp3");
    String[] selectionArgsMp3 = new String[] { mimeType };


    Cursor musicCursor = musicResolver.query(musicUri, projection, selection, selectionArgsMp3, sortOrder);

    if(musicCursor != null && musicCursor.moveToFirst()) {
        int idColumn = musicCursor.getColumnIndex(MediaStore.Audio.Media._ID);
        int titleColumn = musicCursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
        int artistColumn = musicCursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);

        do {
            long id = musicCursor.getLong(idColumn);
            String title = musicCursor.getString(titleColumn);
            String artist = musicCursor.getString(artistColumn);

            //bpm processing
            int bpm = getBpmFromId(id);

            songList.add(new Song(id, title, artist));
        } while (musicCursor.moveToNext());
    }
    if(musicCursor != null)
        musicCursor.close();
}

编辑:似乎可能需要这么长时间才能从Uri获取文件路径,这是通过以下方法完成的:

    public String getRealPathFromURI(Context context, Uri contentUri) {
    Cursor cursor = null;
    try {
        String[] proj = { MediaStore.Images.Media.DATA };
        cursor = context.getContentResolver().query(contentUri,  proj, null, null, null);
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
}

我不确定如何,或者如果我可以,优化它。

1 个答案:

答案 0 :(得分:0)

决定对整个列表使用一个asynctask或将列表用作许多asynctasks的队列取决于您对并发的要求。

  • 如果您打算并行化标记获取,那么使用多个asynctasks(如果操作涉及大量磁盘IO而不是CPU时间,这将是很好的)。
  • 否则,如果您计划按顺序执行它们,那么您应该只使用一个asynctask。没有必要创建,然后摧毁数十/数百个后台线程。这效率很低。