Search code examples
androidandroid-fragmentsexpandablelistadapteraudio-playernotifydatasetchangedandroid-music-player

Data has changed but notifyDataSetChanged not working


I am trying to build a music player. I have a class called MusicData which provides playlist data and another class for playlist fragment since I am using viewpager. The playlist fragment loads the data using a custom expandableListAdapter class.

Now the problem is this. When user clicks a song, it should get added to the recently played playlist and this should reflect in the playlist fragment. The underlying data does change since when I click on the first song from the playlist it does play the same but the view, which contains the title of the song does not change

Therefore the problem in essence is that the views do not reflect the underlying data. I have tried to put notifyDataSetChanged method in the playlist fragment class but it doesn't work. what to do?

Here's the code for playlist fragment class

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.playlist, container, false);
    expandableListView = (ExpandableListView)v.findViewById(R.id.expandableListViewPlaylist);
    Log.e(TAG,"1");
    expandableListTitle = new ArrayList<>(MusicData.getExpandableListDetailPlayList().keySet());
    expandableListAdapter = new CustomExpandableListAdapter(this.getContext(), expandableListTitle, MusicData.getExpandableListDetailPlayList());
    expandableListView.setAdapter(expandableListAdapter);
    expandableListAdapter.notifyDataSetChanged();
    .......

And this is code for MusicData class

public static LinkedHashMap<String, ArrayList<Song>> getExpandableListDetailPlayList(){return expandableListDetailPlayList;}

And this is Adapter

public class CustomExpandableListAdapter extends BaseExpandableListAdapter {

private Context context;
private ArrayList<String> expandableListTitle;
private LinkedHashMap<String, ArrayList<Song>> expandableListDetail;
private String TAG = "AdapterClass";
public CustomExpandableListAdapter(Context context, ArrayList<String> expandableListTitle,
                                   LinkedHashMap<String, ArrayList<Song>> expandableListDetail) {
    this.context = context;
    this.expandableListTitle = expandableListTitle;
    this.expandableListDetail = expandableListDetail;

}

@Override
public Object getChild(int listPosition, int expandedListPosition) {
    return this.expandableListDetail.get(this.expandableListTitle.get(listPosition))
            .get(expandedListPosition);
}

@Override
public long getChildId(int listPosition, int expandedListPosition) {
    return expandedListPosition;
}
......    

The data for the playlist is changed in the MainActivity class. So how and where do I call notifyDataSetChanged() method?


Solution

  • notifyDataSetChanged() is used to notify the adapter that the data has changed. You're using it at the adapter/view setup/creation, which doesn't make any sense. What you should do and what you're probably missing is adding the selected song to the data of the adapter, then calling the notifyDataSetChanged() method

    EDIT : FROM OP

    I tried to implement a listener but couldn't get it to work since the message had to be sent from main activity to the fragment and it seems to me there is no way to do it.

    Anyways, so I tried EventBus as suggested but even then notifyDataSetChanged method did not work, neither did notifyDataSetInvalidated.

    Ultimately I had to write another function in the adapter class which cleared the views and set fresh data. I called this function from Playlist fragment. Here's the code

        public void refresh(ArrayList<String> expandableListTitle,
                        LinkedHashMap<String, ArrayList<Song>> expandableListDetail){
        this.expandableListDetail.clear();
        this.expandableListTitle.clear();
        this.expandableListDetail.putAll(expandableListDetail);
        this.expandableListTitle.addAll(expandableListTitle);
        this.notifyDataSetChanged();
        }
    

    Again I experimented a bit to see what happened if notify method is removed and saw that views did not get updated if the group view is expanded. It got updated when the group view was collapsed and expanded again. So here notify method did work but only after clearing the views. When I didn't clear the views then notify method did not work.

    LESSON Always clear views and infuse fresh data before calling notify method. Maybe on some other Android apis you don't need to clear views and all but I don't think anyone should take a chance. I tested on Android api 19.