2012-05-25 84 views
0

我正在爲android編寫一個小型Google Talk客戶端,並且無法刷新我的ListView correcty。使用自定義適配器刷新ListView

此列表包含聯繫人列表並顯示聯繫人的姓名和聯繫人。我的監聽工作正常,我可以看到在日誌貓窗口中的每個接觸的存在變化,但我的ListView不爽快......這裏是一些代碼:

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; 
} 

}

這工作得很好,一切都顯示正確..唯一的問題似乎是在addRosterListener()方法,其中onPresenceChanged()實現..

這裏是我的適配器:

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; 
} 

}

有什麼我失蹤?

編輯:我改變了這樣的我onPresenceChanged方法:

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(); 
} 

它可以在一定程度上:在屏幕上滑動了一下後,改變了他的存在接觸而出現在名單:/

+1

嘗試runOnUiThread? – ThomasRS

回答

0

當構造一個ArrayAdapter時,它保存傳入的List的引用。如果您要傳入一個Activity,並且稍後更改該Activity成員,那麼ArrayAdapter仍然是持有對原始列表的引用。適配器不知道你改變了列表中的活動。

在我看來,這就是你正在做的事情,所以你需要用新的列表數據重新創建適配器。

或者你可以使用一個ArrayAdapter方法修改底層列表(addinsertremoveclear等),則notifyDataSetChanged WIL工作。

+0

但notifiDadaSetChanged方法在正確的行中被調用? – Marc

+0

它是在對適配器進行更改之後進行的,因此它對我來說很合適。 – Barak