首先让我们看一个客户端图片
这是京东客户端的购物车界面。有这么一种功能,当我们在商品列表中调整商品数量等信息的时候,下方的金额总数也随之变化。
可以看出,这个界面有一个数据源,一个适配器,一个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>
效果图: