1. 程式人生 > >(15)關於ListView中notifyDataSetChanged()重新整理資料不更新原因

(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?在CODE上檢視程式碼片派生到我的程式碼片
  1. publicstatic AccountListAdapter sinaAccountAdapter;  
  2. publicstatic AccountListAdapter tencentAccountAdapter;  
	public static AccountListAdapter sinaAccountAdapter;
	public static AccountListAdapter tencentAccountAdapter;

2、定義資料來源

userInfos存放的是所有帳號的資料,sinaUsers存放的是新浪帳號的資料,tencentUsers存放的是騰訊帳號的資料

[java] view plaincopyprint?在CODE上檢視程式碼片派生到我的程式碼片
  1. publicstatic List<UserInfo> userInfos;  
  2. privatestatic List<UserInfo> sinaUsers;  
  3. privatestatic List<UserInfo> tencentUsers;  
	public static List<UserInfo> userInfos;
	private static List<UserInfo> sinaUsers;
	private static List<UserInfo> tencentUsers;


3、獲取資料

[java] view plaincopyprint?在CODE上檢視程式碼片派生到我的程式碼片
  1. // 獲取資料庫幫助物件
  2.         dataHelper = DataBaseContext.getInstance(mContext);  
  3. // 獲取使用者列表
  4.         userInfos = dataHelper.getUserList(true);  
  5.         setListAdapter();  
// 獲取資料庫幫助物件
		dataHelper = DataBaseContext.getInstance(mContext);
		// 獲取使用者列表
		userInfos = dataHelper.getUserList(true);
		setListAdapter();
[java] view plaincopyprint?在CODE上檢視程式碼片派生到我的程式碼片
  1. privatevoid setListAdapter() {  
  2. // 獲得新浪使用者和騰訊使用者的列表
  3.         getSinaUsers();  
  4.         getTencentUsers();  
  5. if (userInfos.size() == 0) {  
  6.             Toast.makeText(mContext, "您還沒有新增過賬號哦", Toast.LENGTH_LONG).show();  
  7.         }  
  8.         sinaAccountAdapter = new AccountListAdapter(AccountManage.this,  
  9.                 sinaUsers);  
  10.         tencentAccountAdapter = new AccountListAdapter(AccountManage.this,  
  11.                 tencentUsers);  
  12.         accountListView.setAdapter(sinaAccountAdapter);  
  13.     }  
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?在CODE上檢視程式碼片派生到我的程式碼片
  1. // 獲得新浪使用者
  2. privatestatic List<UserInfo> getSinaUsers() {  
  3.     sinaUsers = new ArrayList<UserInfo>();  
  4. for (UserInfo userInfo : userInfos) {  
  5. if (userInfo.getType() == SINA) {  
  6.             sinaUsers.add(userInfo);  
  7.         }  
  8.     }  
  9. return sinaUsers;  
  10. }  
  11. // 獲得騰訊使用者
  12. privatestatic List<UserInfo> getTencentUsers() {  
  13.     tencentUsers = new ArrayList<UserInfo>();  
  14. for (UserInfo userInfo : userInfos) {  
  15. if (userInfo.getType() == TENCENT) {  
  16.             tencentUsers.add(userInfo);  
  17.         }  
  18.     }  
  19. return tencentUsers;  
  20. }  
	// 獲得新浪使用者
	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?在CODE上檢視程式碼片派生到我的程式碼片
  1. publicstaticvoid updateSinaUserList() {  
  2. // 獲取資料庫使用者列表
  3.         userInfos = dataHelper.getUserList(true);  
  4.         List<UserInfo> infos = new ArrayList<UserInfo>();  
  5. for (UserInfo userInfo : userInfos) {  
  6. if (userInfo.getType() == SINA) {  
  7.                 infos.add(userInfo);  
  8.             }  
  9.         }  
  10.         sinaUsers.clear();  
  11.         sinaUsers.addAll(infos);  
  12. // 更新列表
  13.         sinaAccountAdapter.notifyDataSetChanged();  
  14.     }  
  15. publicstaticvoid updateTencentUserList() {  
  16. // 獲取資料庫使用者列表
  17.         userInfos = dataHelper.getUserList(true);  
  18.         List<UserInfo> infos = new ArrayList<UserInfo>();  
  19. for (UserInfo userInfo : userInfos) {  
  20. if (userInfo.getType() == TENCENT) {  
  21.                 infos.add(userInfo);  
  22.             }  
  23.         }  
  24.         tencentUsers.clear();  
  25.         tencentUsers.addAll(infos);  
  26.         tencentAccountAdapter.notifyDataSetChanged();  
  27.     }  
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都是無效的。