简体   繁体   中英

Refreshing a ListView with a custom adapter

I am writing a small google talk client for android and I am having trouble refreshing my ListView correcty.

This list contains the contact list and is showing the name and the presence of the contact. My listener works fine and I can see the presence changes of each contact in the log cat window, but my ListView is not refreshing... here is some code:

package de.marc.messenger;

// ofc here are the imports

public class RosterActivity extends Activity {

private Roster _roster;
private XMPPConnection _connection;
private List<HashMap<String, String>> _buddies;
private BuddyAdapter _adapter;
private ListView _list;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.roster);

    _buddies = new ArrayList<HashMap<String, String>>();
    _connection = LoginActivity.CONNECTION;

    makePauseForRoster();

    _roster = _connection.getRoster();

    addRosterListener();
    fillBuddyList();
    sortBuddyList();
    initializeListView();
}

/**
 * Lets the thread sleep for a second to ensure that the presence of every
 * user will be available
 */
private void makePauseForRoster() {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

/**
 * Adds a listener to the roster, primarily for changes of presence
 */
private void addRosterListener() {
    _roster.addRosterListener(new RosterListener() {
        public void presenceChanged(Presence presence) {
            String user = presence.getFrom().split("/")[0];
            HashMap<String, String> buddy = findBuddyInRoster(user);
            String p = getPresenceString(user);
            buddy.put("presence", p);
            System.out.println(buddy.values().toString()); // this works
            _adapter.notifyDataSetChanged(); // this doesn't
            _list.invalidate(); // this neither
        }
    });
}

/**
 * Fills the list view with the roster entries
 */
private void initializeListView() {

    _adapter = new BuddyAdapter(this, R.layout.roster_item,
            _buddies);

    _list = (ListView) findViewById(R.id.list_roster);
    _list.setAdapter(_adapter);
}

/**
 * Fills the buddy list with relevant data from a RosterEntry. Relevant data
 * is the users' name, email and presence
 */
private void fillBuddyList() {
    // this just fills my list of hashmaps (_buddies)
}

/**
 * Get a predefined String depending on the presence of a user
 */
private String getPresenceString(String user) {
    // something like "available: away ()" -> "away"
}

/**
 * Sorts the buddy list. Only criterion is the presence of the user, because
 * we have linear algorithms for this kind of problem.
 */
private void sortBuddyList() {
    // move all offline contacts to the end
    // move all online contacts to the beginning
    // all other kind of contacts will stay in the middle
}

/**
 * Finds a specific buddy object for a user via his hashed email
 */
private HashMap<String, String> findBuddyInRoster(String user) {
    for (HashMap<String, String> buddy : _buddies) {
        if (user.equals(buddy.get("user"))) {
            return buddy;
        }
    }
    return null;
}

}

This works fine, everything is shown correctly.. only trouble seems to be in the addRosterListener() method, where the onPresenceChanged() is implemented..

Here is my adapter:

package de.marc.messenger;

// as well some imports

public class BuddyAdapter extends ArrayAdapter<HashMap<String, String>> {

private Context _context;
private List<HashMap<String, String>> _map;
    private LayoutInflater _inflater;

public BuddyAdapter(Context context, int id, List<HashMap<String, String>> map) {
    super(context, id, map);
    _context = context;
    _map = map;
            _inflater = (LayoutInflater) _context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    // find view of a single row in a listview
    View row = convertView;
    if (convertView == null) {
        row = _inflater.inflate(R.layout.roster_item, null);
    }

    // get data for a specific row
    String name = _map.get(position).get("name");
    String user = _map.get(position).get("user");
    String presence = _map.get(position).get("presence");

    // extract views from the row view
    TextView nameText = (TextView) row.findViewById(R.id.text_name);
    TextView userText = (TextView) row.findViewById(R.id.text_id);
    ImageView presenceImg = (ImageView) row
            .findViewById(R.id.image_presence);

    // set data in extracted views
    nameText.setText(name);
    userText.setText(user);

    int resource = 0;
    // something is done with this variable
    presenceImg.setImageResource(resource);

    return row;
}

}

Is there anything I am missing?

Edit: I changed my onPresenceChanged method like this:

public void presenceChanged(Presence presence) {
    String user = presence.getFrom().split("/")[0];
    HashMap<String, String> buddy = findBuddyInRoster(user);
    _adapter.remove(buddy);
    String p = getPresenceString(user);
    buddy.put("presence", p);
    _adapter.add(buddy);
    _adapter.notifyDataSetChanged();
}

It works to some extend: After swiping a bit on the screen, the contact that changed his presence is now out of the list :/

When an ArrayAdapter is constructed, it holds the reference for the List that was passed in. If you were to pass in a List that was a member of an Activity, and change that Activity member later, the ArrayAdapter is still holding a reference to the original List . The Adapter does not know you changed the List int he Activity.

It looks to me like that's what you're doing, so you need to recreate the adapter with the new list data.

Or you can use the ArrayAdapter methods to modify the underlying List ( add , insert , remove , clear , etc.) Then notifyDataSetChanged wil work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM