1

I have a huge list of Song objects. Each object holds 4 Strings (title, album, artist, path) and an integer(album_id to get the album art later). However, I need to pass a part of this list or even the whole list to a new activity which will play these songs.

But yeah, you're right! That's a lot of memory! I reduced it by passing only the paths and in the onCreate() method of the new activity I will read all songs on the device and add them only to the playlist if the paths match. This still takes time and maybe more memory than it should take.

What can I do to reduce memory usage and time to get the list of songs from one activity to another?

If the approach to pass a list of paths to the new activity and read the files (directly) by its path was a good idea, how do I do that? So far I have this code but it's inefficient. It takes as argument a list of paths to files we want in our playlist and reads all songs on the external storage. then it'll check each song if its path is inside the pathlist, if not it'll continue.

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;
}
Davlog
  • 2,162
  • 8
  • 36
  • 60

3 Answers3

1

Have you thought of considering a class with a static variable that holds your list ? Something that can be accessed from all activities globally?

something like

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

public MYClass()
{

//Load here
}




}

And You can (optional)use the SingleTon Pattern with this to prevented unwanted errors.

harveyslash
  • 5,906
  • 12
  • 58
  • 111
1

What I would do is provide a singleton which can be accessed anywhere in you application with the confidence only a single instance of the data exists. This is achieved via a private constructor and a public static get(...) method like so...

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() { ... }
}

In which ever activity you may be in, you simply do -> SongStore.get(YourClass.this).getSongs(); to get the Songs.

ChiefTwoPencils
  • 13,548
  • 8
  • 49
  • 75
  • Classical example of memory leak. You should never hold static reference to Context in any way. – kupsef Jun 29 '14 at 10:05
  • Do explain @kupsef. I learned from publications that, at least up 'til now, hold much more credibility than your comment. – ChiefTwoPencils Jun 29 '14 at 10:16
  • You hold a static reference to SongStore --> That holds a reference to Context --> The Context's Activity also hold a refrence to Context. Because of that, GC cannot free the Activity even after the Activity is destroyed, because SongStore's static instance holds it back. However, my words are just words, so here are some more for you:) http://stackoverflow.com/questions/11908039/android-static-fields-and-memory-leaks – kupsef Jun 29 '14 at 10:33
  • All I can say for now is re-read your link. Your accusations seem unwarranted, and in reality, as much as I love this site, a single answer from a single user providing dissimilar code doesn't make me jump away from what I've provided. I've read many discussions on pros/cons of singletons, my original didn't include context but was provided because of stressed importance in my materials - again and *still* seemingly more credible than your last comment- so I'll have to re-research the topic. Thanks. – ChiefTwoPencils Jun 29 '14 at 10:49
  • Allright, officially my comments come without any warranty. You can simple ignore them if you don't like it. The first comment was just a warning for others to avoid static references to Context. – kupsef Jun 29 '14 at 10:56
0

You can access the songs from the ContentProvider, so there is no need to pass them between Activities.

All you have to do is to release the Array of songs in onStop(), so it won't hold the memory while the Activity is in the background.

By releasing I mean:

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

Additionally, if you really want to pass those songs from one Activity to another (in an Intent), this solution would release the songs in that case also.

Timing considerations:

If it really takes a long time to produce the ArrayList of Songs, then you can cache it with the Singleton concept others have already suggested. But you should take care of the static references to avoid memory leaks.

kupsef
  • 3,357
  • 1
  • 21
  • 31
  • If this is what you're referring to as memory leak, realize my answer does not seek to solve issues like serializing the data at appropriate times. That goes without saying. You also do not answer the question directly it seems. – ChiefTwoPencils Jun 29 '14 at 10:21