0

我正在構建一個音樂播放器,它可以從設備上的所有mp3文件獲取BPM ID3v2標記,並允許通過BPM進行排序和過濾。爲了獲得標籤,我使用了mp3agic庫。事實證明,這個標籤獲取需要花費一些時間用於每首歌曲,並且在將每首歌曲添加到我的歌曲列表時執行獲取會使播放器在一段時間內沒有功能。我不確定是否應該在完成構建時在整個列表上使用AsyncTask,或者爲每個項目使用AsyncTask來檢索其BPM並將其插入到歌曲中,或者甚至使用其他更快速的獲取BPM值的方法。任何人都可以提供指導嗎?對RecyclerView中的大量數據執行緩慢的任務

這裏是我的代碼,以獲得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(); 
     } 
    } 
} 

我不知道如何,或者我我可以,優化這一點。

回答

0

決定對整個列表使用一個asynctask或將該列表用作許多asynctasks的隊列取決於您對併發的需求。

  • 如果您打算並行獲取標籤,然後使用多個asynctasks(如果操作涉及大量磁盤IO而非CPU時間,這將會很好)。
  • 否則,如果你打算按順序執行它們,那麼你應該只使用一個asynctask。沒有必要創建,然後銷燬數十個/數百個後臺線程。這是低效的。