21

I have a list that can be updated by the user, but notifyDataSetChanged() is not working on the adapter associated with the listView. I am using it in a fragment. Datbase gets updated, however the adpater doesn't. Following is my implementation:

My Main Fargment:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    myArrayList = new ArrayList<myList>();
    myArrayList = Database.getSharedObject(getActivity()).getMyList();
    if (myArrayList != null && myArrayList.size() > 0) {
        adapter = new myListAdapter(getActivity(), 0, myArrayList);
    }

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View v = inflater.inflate(R.layout.mainfragment, container, false);
    myListView = (ListView) v.findViewById(R.id.my_list_view);
    myListView.setOnItemClickListener(this);
    if (adapter != null) {
        myListView.setAdapter(adapter);
    }

    return v;
}

After some navigations process List gets updated and in my onResume() method I get the updated List from database and call notifyDatasetChanged() method that does not update my view, however corresponding array from DB is updated one.

@Override
public void onResume() {
    super.onResume();
    myArrayList = Database.getSharedObject(getActivity()).getMyList();
    adapter.setItems (myArrayList);
    adapter.notifyDataSetChanged();

}

MyListAdapter

public class MyListAdapter extends ArrayAdapter<Message> {

    private ArrayList<Message> myList;

    /* Context */
    private Context context;

    public void setItems (ArrayList<Message> myList) {
        this.myList = myList;
    }

    public MyListAdapter (Context context, int textViewResourceId, ArrayList<Message> myList) {
        super(context, textViewResourceId, myList);
        this.context = context;
        this.myList = myList;
    }

    @Override
    public View getView (int position, View v, ViewGroup parent) {
        // Keeps reference to avoid future findViewById()
        MyViewHolder viewHolder;

        if (v == null) {
            LayoutInflater li = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = li.inflate(R.layout.list_row, parent, false);

            viewHolder = new MyViewHolder();
            viewHolder.txtImage = (ImageView) v.findViewById(R.id.message_icon);
            viewHolder.txtMessage = (TextView) v.findViewById(R.id.message);
            viewHolder.txtDate = (TextView) v.findViewById(R.id.date);

            v.setTag(viewHolder);
        } else {
            viewHolder = (MyViewHolder) v.getTag();
        }

        Message myMessage = new Message();
        myMessage = myList.get(position);
        if (myMessage != null) {
            viewHolder.txtMessage.setText(myMessage.getText());
            viewHolder.txtDate.setText(myMessage.getDate());
        }
        return v;
    }

    static class MyViewHolder {
        ImageView txtImage;
        TextView txtMessage;
        TextView txtDate;
    }
}

Any thought on what is going wrong? Why is not listview getting updated? Any helps is appreciated.

vdegenne
  • 12,272
  • 14
  • 80
  • 106
Usama Sarwar
  • 8,922
  • 7
  • 54
  • 80

5 Answers5

37

notifyDataSetChanged() won't work for you. Reasons why

  1. Your adapter loses reference to your list.
  2. Always creating and adding a new list to the Adapter. Do like this: initialize the ArrayList while declaring globally.

ArrayList<MyItemType> myArrayList=new ArrayList<>(); // as a global variable

Add List to the adapter directly without checking null and empty condition. Set the adapter to the list directly(don't check for any condition)

myListView.setAdapter(adapter);

  1. Add data to the myArrayList Every time(if your data is completely new, then you can call adapter.clear() and myArrayList.clear() before actually adding data to the list) but don't set the adapter i.e If the new data is populated in the myArrayList, then just adapter.notifyDataSetChanged()

     adapter = new myListAdapter(getActivity(), 0, myArrayList);
    
  2. Remove this line

    adapter.setItems (myArrayList);

Jorge Gil
  • 4,265
  • 5
  • 38
  • 57
Pragnani
  • 20,075
  • 6
  • 49
  • 74
  • not a good thing to always give the new list instead @hovo888s solution worked – jayant singh Jan 26 '17 at 18:04
  • @jayantsingh Posted 3 years ago, not sure about the context now... but the answer should have been based on the context of the problem.When I quickly look at the question now, I can see that he is using Fragments. when you are switching the fragments you need to do that way, because data will be lost when switching between them – Pragnani Jan 27 '17 at 20:07
  • we can have a function say setItems() which will change the list(data) and notify .so just call the function instead of defining repeatedly – jayant singh Jan 27 '17 at 20:14
  • @jayantsingh you should post that as the answer. If you have setItems(list) rather than sending list upon initialization, you must call setItems(list) rather than notifyDataSetChanged() – Sharone Lev Mar 28 '20 at 19:14
13

Just overrige getCount method

    @Override
    public int getCount() {
        return myArrayList.count();
    }
hov.terteryan
  • 758
  • 6
  • 16
7

In your setItems method try to clear the old ArrayList.

instead of this:

public void setItems(ArrayList<Message> myList) {
this.myList = myList;
}

Try this:

public void setItems(ArrayList<Message> myList) {
this.myList.clear();
this.myList.addAll(myList);
notifyDataSetChanged();
}
Igor Fridman
  • 1,267
  • 1
  • 16
  • 30
0

The problem is in the constructor of MyListAdapter

Instead of

public MyListAdapter(Context context, int textViewResourceId, ArrayList<Message> myList) {
    super(context, textViewResourceId, scheduledMessageList);
    this.context = context;
    this.myList = myList;
}

try

public MyListAdapter(Context context, int textViewResourceId, ArrayList<Message> myList) {
    super(context, textViewResourceId, myList);
    this.context = context;
    this.myList = myList;
}

also instead of you own Method setItems you should call adapter.clear(); followed by adapter.addAll(myArrayList);

Pratik Butani
  • 60,504
  • 58
  • 273
  • 437
Yalla T.
  • 3,707
  • 3
  • 23
  • 36
-3

If you can use notifyDataSetChanged() but in Adapter ! create a little method inside

Blackbelt
  • 156,034
  • 29
  • 297
  • 305
Nicolas
  • 5,249
  • 3
  • 19
  • 20