android - How to sort List<Map<String, String>>
-
21-12-2019 - |
Question
I am using a simple adapter to fill a listview, I can't find how to order items by a specific attribute of the groupData, here is my code:
public class LibraryFragment extends Fragment {
private Context mContext;
private ListView listView1;
private ListAdapter adapter;
private List<Map<String, String>> groupData;
private Map<String, String> group;
private String[] from = new String[] {"url", "title", "artist", "duration"};
private int[] to = new int[] {R.id.url, R.id.title, R.id.artist, R.id.duration};
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_library, container, false);
mContext = getActivity();
listView1 = (ListView) rootView.findViewById(R.id.listView1);
fillLibrary();
return rootView;
}
public void fillLibrary(){
ArrayList<Map<String, String>> groupData = new ArrayList<Map<String, String>>();
File music = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + Environment.DIRECTORY_MUSIC + "/myapp");
if (music.isDirectory()){
File tracks[] = music.listFiles();
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
for (int i = 0; i < tracks.length; i++) {
File track = tracks[i];
String trackPath = track.getAbsolutePath();
String trackName = track.getName();
String trackExt = trackName.substring(trackName.lastIndexOf('.') + 1);
if(trackExt.equals("MP3")||trackExt.equals("mp3"))
{
mmr.setDataSource(trackPath);
// -- create record
HashMap<String, String> group = new HashMap<String, String>();
group.put( "url", trackPath);
group.put( "title", mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE));
group.put( "artist", mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST));
group.put( "duration", getDurationString(Integer.parseInt(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION))/1000));
groupData.add(group);
}
}
Collections.sort(groupData, Functions.mapComparator);
adapter = new SimpleAdapter(mContext , groupData, R.layout.library_item,
from,
to );
listView1.setAdapter( adapter );
}
}
}
And here is my functions Functions.mapComparator
public static Comparator<Map<String, String>> mapComparator = new Comparator<Map<String, String>>() {
public int compare(Map<String, String> m1, Map<String, String> m2) {
return m1.get("title").compareTo(m2.get("title"));
}
};
Do you know what I m doing wrong?
EDIT: Here is the logcat
01-09 20:06:12.005: D/AndroidRuntime(10685): Shutting down VM
01-09 20:06:12.005: W/dalvikvm(10685): threadid=1: thread exiting with uncaught exception (group=0x40d31930)
01-09 20:06:12.065: E/AndroidRuntime(10685): FATAL EXCEPTION: main
01-09 20:06:12.065: E/AndroidRuntime(10685): java.lang.NullPointerException
01-09 20:06:12.065: E/AndroidRuntime(10685): at com.myapp.mobile.Functions$1.compare(Functions.java:44)
01-09 20:06:12.065: E/AndroidRuntime(10685): at com.myapp.mobile.Functions$1.compare(Functions.java:1)
Solution
- Looks like one of your Maps does not contain a value for "title", or it is
null
. - Wouldn't it be easier to use an Object instead of a Map to store your data? Like
new Song(url, title, artist, duration);
. It could implementComparable
, that way you don't need theComparator
anymore.
OTHER TIPS
MediaMetadataRetriever.extractMetadata() can return null, and that's what you're getting. This is probably because some of the music files you are trying to retrieve don't have title information embedded. You should check the return value of extractMetadata()
before adding it.
A simple check like:
String title = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
if (title == null) continue;
will ignore any of those entries without titles (though note the other attributes can also be null, even if a title is set) by skipping to the next entry without adding.