2014-06-29 18 views
1

我有一個巨大的listSong對象。每個對象包含4個Strings(標題,專輯,藝術家,路徑)和integer(album_id以稍後獲取專輯封面)。但是,我需要將此列表的一部分或甚至整個list傳遞給將播放這些歌曲的新activityAndroid Java - 傳遞對象列表(內存浪費)

但是,是的,你是對的!這是很多的記憶!我通過僅傳遞路徑來減少它,並且在新活動的onCreate()方法中,我將讀取設備上的所有歌曲,並在路徑匹配時將它們僅添加到播放列表。這仍然需要時間,並且可能比它應該更多的記憶。

怎樣才能減少內存使用量和時間,以便將歌曲的list從一個活動轉移到另一個活動?

如果將路徑列表傳遞給新活動並通過其路徑讀取文件(直接)是一個好主意,我該怎麼做?到目前爲止,我有這個代碼,但效率不高。它將我們想要的播放列表中的文件的路徑列表作爲參數,並讀取外部存儲中的所有歌曲。那麼它會檢查每首歌曲的路徑是否在路徑列表中,否則它將繼續。

public static List<Song> getSongList(List<String> pathList, Context c) { 
    Cursor audioCursor = c.getContentResolver().query(
      MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, 
      new String[] { "*" }, null, null, Media.TITLE + " ASC"); 
    ArrayList<Song> songsList = new ArrayList<Song>(); 

    if (audioCursor != null) { 
     if (audioCursor.moveToFirst()) { 

      do { 
       String path = audioCursor.getString(audioCursor 
         .getColumnIndex(MediaStore.Audio.Media.DATA)); 


       if(!pathList.contains(path)){ 
        //if it's not in the list, we don't want it! 
        continue; 
       } 

       String title = audioCursor.getString(audioCursor 
         .getColumnIndex(MediaStore.Audio.Media.TITLE)); 
       String album = audioCursor.getString(audioCursor 
         .getColumnIndex(MediaStore.Audio.Media.ALBUM)); 
       String artist = audioCursor.getString(audioCursor 
         .getColumnIndex(MediaStore.Audio.Media.ARTIST)); 
       int album_id = audioCursor.getInt(audioCursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID)); 

       Song s = new Song(); 
       s.setPath(path); 
       s.setTitle(title); 
       s.setArtist(artist); 
       s.setAlbum(album); 
       s.setAlbumId(album_id); 

       songsList.add(s); 

      } while (audioCursor.moveToNext()); 
     } 
    } 
    // return songs list array 
    return songsList; 
} 
+2

我會建議使用單例,比如'SongStore'或類似的。有些人可能會不同意。 – ChiefTwoPencils

+0

您可以使用進度條將列表加載到您的活動中。 – penkzhou

+2

有很多方法,在我看來,單身人士是一種(不壞)的方法。 –

回答

1

你有沒有想過考慮一個靜態變量持有你的列表類?可以從全球所有活動中訪問的東西?

public class MYClass 
{ 
public static ArrayList<Song> Songs; 

public MYClass() 
{ 

//Load here 
} 




} 

,您可以(可選)使用Singleton模式與此有關防止不必要的錯誤。

1

我會做的就是提供一個singleton,它可以在應用程序中的任何地方訪問,只有一個數據實例存在。這是通過private構造和public static get(...)方法,像這樣實現...

public class SongStore { 

    private static SongStore sSongStore; 
    private Context mContext; 
    private ArrayList<Song> mSongList; 

    private SongStore(Context context) { 
     mContext = context; 
     loadData(); 
    } 

    public static SongStore get(Context context) { 
     if (sSongStore == null) { 
      sSongStore = new SongStore(context.getApplicationContext()); 
     } 
     return sSongStore; 
    } 

    private void loadData() { 
     // load the data 
    } 

    public ArrayList<Song> getSongs() { ... } 
} 

在其以往的活動,你可以,你只需做 - >SongStore.get(YourClass.this).getSongs();得到Song秒。

+0

內存泄漏的經典示例。您絕不應該以任何方式持有對Context的靜態引用。 – kupsef

+0

解釋@kupsef。我從出版物中瞭解到,至少現在至少比你的評論更可靠。 – ChiefTwoPencils

+0

您持有對SongStore的靜態引用 - >包含對上下文的引用 - >上下文的活動也包含對上下文的引用。因此,即使在活動被銷燬之後,GC也不能釋放活動,因爲SongStore的靜態實例將其保留。然而,我的話只是文字,所以這裏有一些更適合你:) http://stackoverflow.com/questions/11908039/android-static-fields-and-memory-leaks – kupsef

0

您可以訪問ContentProvider中的歌曲,因此無需在Activities之間傳遞歌曲。

您只需要發佈onStop()中的Array歌曲,因此在Activity處於後臺時它不會佔用內存。

通過釋放我的意思是:

public void onStop(){ 
    this.songsList = null; 
} 

此外,如果你真的想從一個活動傳遞這些歌曲到另一個(在一個Intent),該解決方案將釋放的歌曲在這種情況下也。

時機的考慮:

如果真的需要很長的時間來產生歌曲的ArrayList中,然後就可以用辛格爾頓概念別人緩存它已經建議。但你應該照顧靜態引用以避免內存泄漏。

+0

如果這就是你所說的內存泄漏,意識到我的答案並不尋求解決在適當的時候序列化數據的問題。那不用說了。你也不會直接回答這個問題。 – ChiefTwoPencils