0

I call

adapter.notifyDataSetChanged();

but nothing happens UNTIL I click the list view to scroll it, then the list view updates. I want it to update automatically.. what should I do?

I have tried this answer but it didn't worked for me

Obs: I'm using a custom array adapter. Its a chat app that needs to update its online users automatically.

Here's how I declare the adapter and the array adapter (onCreate) with a button that calls an AsyncTask, I call the notifyDataSetChanged inside the AsyncTask but inside onPostExecute:

peopleList = (ListView) findViewById(R.id.peopleList);
adapter = new MyAdapter(this, people);
peopleList.setAdapter(adapter);
btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            new ConnectAndLoad(MainActivity.this).execute();
        }
    });

This is my Adapter:

public class PeopleAdapter extends ArrayAdapter<People> {
    private ArrayList<People> events_list = new ArrayList<>();
    Context context;
    public PeopleAdapter(Context context, ArrayList<People> users) {
        super(context, 0, users);
        this.context = context;
        this.events_list = users;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        People user = getItem(position);

        if (convertView == null) {
            convertView = LayoutInflater.from(getContext()).inflate(R.layout.people_list, parent, false);
        }

        TextView tvName = (TextView) convertView.findViewById(R.id.name);
        TextView tvStatus = (TextView) convertView.findViewById(R.id.status);
        tvName.setText(user.name);
        tvStatus.setText(user.status);

        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context, "You Clicked " + events_list.get(position).name, Toast.LENGTH_SHORT).show();
                Intent i = new Intent(context, ConversationActivity.class);
                i.putExtra("user", events_list.get(position).name);
                context.startActivity(i);
            }
        });

        return convertView;
    }
}

Finally here is the AsyncTask's onPostExecute that calls notifyDataSetChanged, everytime a user has its presence changed it is supposed to add the new user to the people list, and then call the notifyDataSetChanged (It adds the new person to the list and it actually changes the data set, the ONLY problem is that I only see the updated list once I click the listview!):

protected void onPostExecute(Boolean boo) {
    roster.addRosterListener(new RosterListener() {

            public void entriesDeleted(Collection<String> addresses) {
            }

            public void entriesUpdated(Collection<String> addresses) {
            }

            public void entriesAdded(Collection<String> addresses) {
            }

            @Override
            public void presenceChanged(Presence presence) {
                people.add(new People(presence.getFrom(), presence.getStatus()));
                adapter.notifyDataSetChanged();
            }
        });
    dialog.dismiss();
}

EDIT: I followed what @savepopulation said and took the adapter.notifyDataSetChanged(); out of presenceChanged and it worked. BUT I need this to be inside the presenceChanged so it updates when users go online and offline. If you guys have any advice please let me know :)

Community
  • 1
  • 1
gooeyn
  • 90
  • 8
  • Please add more code. Could you add your activity file where you declare the adapter and array adapter (if you have a custom one) – Keith Dec 07 '15 at 20:16
  • Are you calling that in an async method perhaps? -> need to use runUIThread() – Tim Dec 07 '15 at 20:19
  • It's hard to find a solution without code but according to your post, there's an other operation which blocks your ui thread. ı suggest you to check how you change adapter data. Can you send the code where you change adapter items? – savepopulation Dec 07 '15 at 20:22
  • @savepopulation added the code,please check it out – gooeyn Dec 07 '15 at 20:34
  • @TimCastelijns added the code,please check it out and yes I'm usig AsyncTask but I'm calling it inside onPostExecute which I assume runs on the UI thread? – gooeyn Dec 07 '15 at 20:35
  • @Keith hey, I added the code. please check it out – gooeyn Dec 07 '15 at 20:35
  • can you take adapter.notifyDataSetChanged(); just out of method over dialog.dismiss and try again? – savepopulation Dec 07 '15 at 20:43
  • @savepopulation just did as you said and it actually worked. But I don't know what I should do then.. it needs to update as new users go online or offline. Do you have any advice for this situation? Thank you anyway! – gooeyn Dec 07 '15 at 20:48
  • I don't have any idea about what you are trying to do. only i can say, your presencechanged method calls before your adapter gets notified successfully. so this's blocking your ui thread. if you tell me what you're excatly trying to do we can figure out a more adaptive solution. by the way if you upvote my answer, l'll be glad. – savepopulation Dec 07 '15 at 20:51
  • @savepopulation I would love to do that but I'm a new user and I don't see any up arrows when I hover any comment.. I guess I don't have this privilege yet, I'm sorry.. As soon as I can do that I promise you I will. – gooeyn Dec 07 '15 at 20:57
  • @savepopulation about what I'm trying to do: it's a basic chat app that has online and offline users. I'm using the XMPP protocol and the Smack library for that protocol. The method presenceChanged is called every time an user changes its status (online-offline), so I would update the list view (which contains online users) when an user goes online.. – gooeyn Dec 07 '15 at 21:00
  • Okey. Let me a few minutes and i'll post an answer. – savepopulation Dec 07 '15 at 21:02

1 Answers1

1

Here we go.

First of all when you call adapter.notifyDataSetChanged(); ListView or RecyclerView if your data changes or some of your methods such as onClick or onItemClickListener only works after you click to your view or scroll your view this means something is blocking your UiThread and your UiThread gets unblocked after you interrupt.

Probably this caused by your notify call. You're trying to notify your adapter before your previous notify operation completed. I think this causes your problem.

I don't know if there's an other efficient way to to what you're trying to implement but if you must notify in your presenceChanged method just notify item which one's data has changed.

You can use RecyclerView instead of ListView and use notifyItemChanged method. Just notify the item which changed. Do not notify whole list. This can solve your problem. Also you can take notify method out of onPresenceChanged method. This solves your problem but it's not suitable for your business.

If notifying the single changed item does not work for you, you'll probably need to change your implementation.

Good luck.

Damian Kozlak
  • 7,065
  • 10
  • 45
  • 51
savepopulation
  • 11,736
  • 4
  • 55
  • 80