首先讓我們看一個客戶端圖片
這是京東客戶端的購物車界面。有這么一種功能,當我們在商品列表中調整商品數量等信息的時候,下方的金額總數也隨之變化。
可以看出,這個界面有一個數據源,一個適配器,一個ListView。 總金額的布局是顯示在ListView布局上面的。
那么怎么樣可以當列表數據源變化的時候,下方的總金額(ListView 之外的UI)也變化?
有兩個思路:
1、我們點擊某一個列表項的某一個按鈕時(可能是刪除此商品按鈕,可能是調整此商品數量按鈕)的時候,對應執行監聽事件接口回調的時候計算一下列表數據源數據得到的總金額。顯示在UI中。 但是這種方法當列表項中能決定總金額的按鈕比較多的時候,就會造成代碼冗余。
2、給適配器設定一個觀察者。當數據源發生變化的時候,觀察者觀察到並執計算總金額修改UI
我們這里學習第二種思路。
------------------------------------------------------------------------------------------------------------
一、首先,讓我們看一下觀察者模式的介紹:
觀察者模式(Observer)完美的將觀察者和被觀察的對象分離開。
舉個例子,用戶界面可以作為一個觀察者,業務數據是被觀察者,用戶界面觀察業務數據的變化,發現數據變化后,就顯示在界面上。面向對象設計的一個原則是:系統中的每個類將重點放在某一個功能上,而不是其他方面。一個對象只做一件事情,並且將他做好。觀察者模式在模塊之間划定了清晰的界限,提高了應用程序的可維護性和重用性。
觀察者設計模式定義了對象間的一種一對多的依賴關系,以便一個對象的狀態發生變化時,所有依賴於它的對象都得到通知並自動刷新。
二、Adapter本身包含一個觀察者模式 DataSetObserver
注意:DataSetObserver 是一個抽象類,使用的時候需要創建子類,不是接口。
Adapter可以注冊多個數據觀察者 registerDataSetObserver
三、DataSetObserver的使用
1、創建觀察者對象
private DataSetObserver sumObserver = new DataSetObserver() { /** * 當Adapter的notifyDataSetChanged方法執行時被調用 */ @Override public void onChanged() { super.onChanged();
//執行相應的操作 } /** * 當Adapter 調用 notifyDataSetInvalidate方法執行時被調用 */ @Override public void onInvalidated() { super.onInvalidated();
//執行相應的操作 } };
2、注冊觀察者
在onCreat()方法中
//設置Adapter的數據變化觀察者,只要Adapter的notifyDataSet被調用,觀察者自動調用 adapter.registerDataSetObserver(sumObserver);
3、注銷觀察者
在適當的位置注銷觀察者
比如在onDestroy()方法中注銷
@Override protected void onDestroy() { super.onDestroy(); adapter.unregisterDataSetObserver(sumObserver); }
四、Demo
當ListView數據源發生變化時UI發生變化。初始所有列表項都為0,點擊變為2,查看總金額變化

1 package com.xqx.adapterobserver; 2 3 import android.app.Activity; 4 import android.database.DataSetObserver; 5 import android.os.Bundle; 6 import android.view.View; 7 import android.widget.*; 8 import org.w3c.dom.Text; 9 10 import java.util.ArrayList; 11 import java.util.List; 12 13 public class MainActivity extends Activity { 14 /** 15 * Called when the activity is first created. 16 */ 17 18 private ArrayAdapter<Integer> adapter ; 19 private List<Integer> list; 20 private ListView listView; 21 private TextView text; 22 23 //創建觀察者 24 private DataSetObserver sumObserver = new DataSetObserver() { 25 /** 26 * 當Adapter的notifyDataSetChanged方法執行時被調用 27 */ 28 @Override 29 public void onChanged() { 30 super.onChanged(); 31 //執行相應的操作 32 int sum = 0; 33 for (int i = 0; i < list.size(); i++) { 34 sum+=list.get(i); 35 } 36 text.setText("總金額:"+sum); 37 } 38 39 /** 40 * 當Adapter 調用 notifyDataSetInvalidate方法執行時被調用 41 */ 42 @Override 43 public void onInvalidated() { 44 super.onInvalidated(); 45 //執行相應的操作 46 } 47 }; 48 @Override 49 public void onCreate(Bundle savedInstanceState) { 50 super.onCreate(savedInstanceState); 51 setContentView(R.layout.main); 52 53 list = new ArrayList<Integer>(); 54 for (int i = 0; i < 30; i++) { 55 list.add(0); 56 } 57 adapter = new ArrayAdapter<Integer>(this,android.R.layout.simple_list_item_1,list); 58 //注冊觀察者 59 adapter.registerDataSetObserver(sumObserver); 60 text = (TextView) findViewById(R.id.text); 61 listView = (ListView) findViewById(R.id.listView); 62 listView.setAdapter(adapter); 63 64 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 65 @Override 66 public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { 67 list.set(i,2); 68 //將列表項的0變為2 更新適配器, 69 adapter.notifyDataSetChanged(); 70 //執行該方法后DataSetObserver觀察者觀察到 71 } 72 }); 73 74 } 75 76 @Override 77 protected void onDestroy() { 78 super.onDestroy(); 79 //注銷觀察者 80 adapter.unregisterDataSetObserver(sumObserver); 81 } 82 }

1 <?xml version="1.0" encoding="utf-8"?> 2 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="vertical" 4 android:layout_width="fill_parent" 5 android:layout_height="fill_parent" 6 > 7 <ListView 8 android:id="@+id/listView" 9 android:layout_width="match_parent" 10 android:layout_height="match_parent" 11 > 12 13 </ListView> 14 15 <LinearLayout 16 android:layout_width="match_parent" 17 android:layout_height="50dp" 18 android:background="#ccc" 19 android:layout_gravity="bottom" 20 > 21 <TextView 22 android:id="@+id/text" 23 android:layout_width="wrap_content" 24 android:layout_height="wrap_content" 25 android:textSize="25sp" 26 android:textColor="#000" 27 android:text="總金額" 28 /> 29 </LinearLayout> 30 31 </FrameLayout>
效果圖: