(15)關於ListView中notifyDataSetChanged()重新整理資料不更新原因
使用Listview的時候: 當要動態顯示更改後的資料(例如資料庫改動), 很多人應該都用過notifyDataSetChanged();這個方法來重新整理Listview,顯示改後的資料.
這時候就要注意了:
......
private ArrayList<HashMap<String, Object>> usersList;
......
usersList= query(......); //根據查詢函式獲取一個ArrayList並賦值給繫結到Adapter的資料來源usersList
sAdapter.notifyDataSetChanged();
......
如果你也是: 上面這種形式去重新整理ListView的資料的話, 是不可以更新的. 必須改成如下形式:
......
//usersList= query(......);
usersList.clear();
usersList.addAll(query(......));
sAdapter.notifyDataSetChanged();
///////////////////////////////////////////////////////////////////////////////////////
原因是: sAdapter會通過usersList獲取List中的內容。但是實際上可能(也應該)是,在呼叫super(MyActivity.this, R.layout.item, usersList)時sAdapter儲存了usersList指向原List(假設為List a)的引用,在呼叫query函式之後,usersList指向了一個新的List(List b)。但是在呼叫notifyDataSetChanged()時,sAdapter會跟據儲存的引用(即指向List a的引用)去更新,因此當然還是原來的結果,不會進行更新。
注意:第一次進入activity可以的,按返回鍵後,再次進入的時候不顯示資料原因:第一次進入呼叫了onCreate()方法,當這個Activiy失去焦點,即你跳轉到了其他頁面,當返回時這個Activity不會執行onCreate(),方法,這時得到焦點,執行onResume()方法,所以你可以重寫這個onResume()方法,在這個方法裡面用上面講到的那個方法就可以了。
下面引用別人做好的一個真例項子:
關於ListView中adapter呼叫notifyDataSetChanged無效的原因
話說這個問題已經困擾我很久了,一直找不到原因,我以為只要資料變了,呼叫adapter的notifyDataSetChanged就會更新列表,最近在做微博帳號管理這一塊,想著動態更新列表,資料是變了,但就是沒有把更新的資料顯示出來。為什麼是這樣,以下是我總結的一些原因:
1、資料來源沒有更新,呼叫notifyDataSetChanged無效。
2、資料來源更新了,但是它指向新的引用,呼叫notifyDataSetChanged無效。
3、資料來源更新了,但是adpter沒有收到訊息通知,無法動態更新列表。
我遇到的問題的原因是第2條,資料來源更新了,但它指向新的引用,這樣說很抽象,拿具體例子來說吧,
我們在顯示ListView資料的時候,首先需要一個數據介面卡,叫做adapter的東西
1、定義兩個介面卡:
1個是新浪微博帳號的介面卡,另一個是騰訊微博帳號的介面卡
[java] view plaincopyprint?- publicstatic AccountListAdapter sinaAccountAdapter;
- publicstatic AccountListAdapter tencentAccountAdapter;
public static AccountListAdapter sinaAccountAdapter;
public static AccountListAdapter tencentAccountAdapter;
2、定義資料來源
userInfos存放的是所有帳號的資料,sinaUsers存放的是新浪帳號的資料,tencentUsers存放的是騰訊帳號的資料
[java] view plaincopyprint?- publicstatic List<UserInfo> userInfos;
- privatestatic List<UserInfo> sinaUsers;
- privatestatic List<UserInfo> tencentUsers;
public static List<UserInfo> userInfos;
private static List<UserInfo> sinaUsers;
private static List<UserInfo> tencentUsers;
3、獲取資料
- // 獲取資料庫幫助物件
- dataHelper = DataBaseContext.getInstance(mContext);
- // 獲取使用者列表
- userInfos = dataHelper.getUserList(true);
- setListAdapter();
// 獲取資料庫幫助物件
dataHelper = DataBaseContext.getInstance(mContext);
// 獲取使用者列表
userInfos = dataHelper.getUserList(true);
setListAdapter();
[java]
view plaincopyprint?
- privatevoid setListAdapter() {
- // 獲得新浪使用者和騰訊使用者的列表
- getSinaUsers();
- getTencentUsers();
- if (userInfos.size() == 0) {
- Toast.makeText(mContext, "您還沒有新增過賬號哦", Toast.LENGTH_LONG).show();
- }
- sinaAccountAdapter = new AccountListAdapter(AccountManage.this,
- sinaUsers);
- tencentAccountAdapter = new AccountListAdapter(AccountManage.this,
- tencentUsers);
- accountListView.setAdapter(sinaAccountAdapter);
- }
private void setListAdapter() {
// 獲得新浪使用者和騰訊使用者的列表
getSinaUsers();
getTencentUsers();
if (userInfos.size() == 0) {
Toast.makeText(mContext, "您還沒有新增過賬號哦", Toast.LENGTH_LONG).show();
}
sinaAccountAdapter = new AccountListAdapter(AccountManage.this,
sinaUsers);
tencentAccountAdapter = new AccountListAdapter(AccountManage.this,
tencentUsers);
accountListView.setAdapter(sinaAccountAdapter);
}
從setListAdapter這個方法中,我們可以看到,sinaAccountAdapter的資料來源是sinaUsers,而tencentAccountAdapter的資料來源是tencentUsers,他們分別通過getSinaUsers()、getTencentUser()方法得到
[java] view plaincopyprint?- // 獲得新浪使用者
- privatestatic List<UserInfo> getSinaUsers() {
- sinaUsers = new ArrayList<UserInfo>();
- for (UserInfo userInfo : userInfos) {
- if (userInfo.getType() == SINA) {
- sinaUsers.add(userInfo);
- }
- }
- return sinaUsers;
- }
- // 獲得騰訊使用者
- privatestatic List<UserInfo> getTencentUsers() {
- tencentUsers = new ArrayList<UserInfo>();
- for (UserInfo userInfo : userInfos) {
- if (userInfo.getType() == TENCENT) {
- tencentUsers.add(userInfo);
- }
- }
- return tencentUsers;
- }
// 獲得新浪使用者
private static List<UserInfo> getSinaUsers() {
sinaUsers = new ArrayList<UserInfo>();
for (UserInfo userInfo : userInfos) {
if (userInfo.getType() == SINA) {
sinaUsers.add(userInfo);
}
}
return sinaUsers;
}
// 獲得騰訊使用者
private static List<UserInfo> getTencentUsers() {
tencentUsers = new ArrayList<UserInfo>();
for (UserInfo userInfo : userInfos) {
if (userInfo.getType() == TENCENT) {
tencentUsers.add(userInfo);
}
}
return tencentUsers;
}
我現在要定義動態更新兩個帳號列表的方法
[java] view plaincopyprint?- publicstaticvoid updateSinaUserList() {
- // 獲取資料庫使用者列表
- userInfos = dataHelper.getUserList(true);
- List<UserInfo> infos = new ArrayList<UserInfo>();
- for (UserInfo userInfo : userInfos) {
- if (userInfo.getType() == SINA) {
- infos.add(userInfo);
- }
- }
- sinaUsers.clear();
- sinaUsers.addAll(infos);
- // 更新列表
- sinaAccountAdapter.notifyDataSetChanged();
- }
- publicstaticvoid updateTencentUserList() {
- // 獲取資料庫使用者列表
- userInfos = dataHelper.getUserList(true);
- List<UserInfo> infos = new ArrayList<UserInfo>();
- for (UserInfo userInfo : userInfos) {
- if (userInfo.getType() == TENCENT) {
- infos.add(userInfo);
- }
- }
- tencentUsers.clear();
- tencentUsers.addAll(infos);
- tencentAccountAdapter.notifyDataSetChanged();
- }
public static void updateSinaUserList() {
// 獲取資料庫使用者列表
userInfos = dataHelper.getUserList(true);
List<UserInfo> infos = new ArrayList<UserInfo>();
for (UserInfo userInfo : userInfos) {
if (userInfo.getType() == SINA) {
infos.add(userInfo);
}
}
sinaUsers.clear();
sinaUsers.addAll(infos);
// 更新列表
sinaAccountAdapter.notifyDataSetChanged();
}
public static void updateTencentUserList() {
// 獲取資料庫使用者列表
userInfos = dataHelper.getUserList(true);
List<UserInfo> infos = new ArrayList<UserInfo>();
for (UserInfo userInfo : userInfos) {
if (userInfo.getType() == TENCENT) {
infos.add(userInfo);
}
}
tencentUsers.clear();
tencentUsers.addAll(infos);
tencentAccountAdapter.notifyDataSetChanged();
}
以上的兩個方法是可以實現動態更新列表的,因為它是同一個資料來源,並沒有指向新的引用,我之前是直接呼叫getSinaUsers()和getTencentUsers()方法,這相當於重新new了一個List,並不是原來的資料來源,所以無論怎麼呼叫notifyDataSetChanged都是無效的。