1.Adapter设计模式
Android中adapter接口有很多种实现,例如,ArrayAdapter,BaseAdapter,CursorAdapter,SimpleAdapter,SimpleCursorAdapter等,他们分别对应不同的数据源。例如,ArrayAdater对应List和数组数据源,而CursorAdapter对应Cursor对象(一般从数据库中获取的记录集)。这些Adapter都需要getView方法返回当前列表项显示的View对象。当Model发生改变时,会调用BaseAdapter.notifyDataSetChanged方法通知组件数据已经改变,这时Adapter会调用getView方法用于重新显示组件中的内容。当组件中显示的数据变化时,如删除一个项表项,组件回调Adapter中getView方法用于重新显示组件中的内容。当组件中显示的数据变化时,如删除一个项表项,组件会通知Adapter中方法删除Model中相应的记录,然后再调用BaseAdapter.notifyDataSetChanged方法使组件中显示数据发生变化。总之一句话,无论数据变化还是组件显示数据发送变化,都需要将Adpter作为桥梁来达到View和Model之间同步的目的。
Android中Adapter是非常明显的MVC模式。
2.Adapter内部实现原理
下面我们以ListView和BaseAdapter为例,说明其原理。
原理:ListView中List的每个item,向adapter请求一个视图View,然后Adapter中getView方法创建一个新的或从缓存区中获取View修改ViewHoler内容,然后显示。Android中为我们提供了View缓存并不是每个新的item需要新建一个新视图,Android中通过有个叫做Recycler的构件实现。
通过上图可知,AndroidListView只在刚开始convertView为空时,才创建新的View。这既减轻了内存的压力,又提高的ListView滑动时的更新的性能和用户体验。
3.代码演示
ListView+BaseAdapter,MyAdaoter继承BaseAdapter,实现其方法,关键在getView()。
1 class MyAdapter extends BaseAdapter{ 2 3 private List<Map<String,String>> datas=new ArrayList<Map<String,String>>(); 4 private LayoutInflater mInflater; 5 private static final int TYPE_ITEM = 0; 6 private static final int TYPE_SEPARATOR = 1; 7 private static final int TYPE_MAX_COUNT = TYPE_SEPARATOR + 1; 8 private TreeSet mSeparatorsSet = new TreeSet(); 9 10 public MyAdapter() { 11 mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); 12 } 13 //添加项目 14 public void add(Map<String,String> item){ 15 datas.add(item); 16 notifyDataSetChanged(); 17 } 18 //添加分割栏 19 public void addSeparator(Map<String,String> item){ 20 datas.add(item); 21 mSeparatorsSet.add(datas.size()-1); 22 notifyDataSetChanged(); 23 } 24 @Override 25 public int getItemViewType(int position) { 26 return mSeparatorsSet.contains(position)?TYPE_SEPARATOR:TYPE_ITEM; 27 } 28 29 @Override 30 public int getViewTypeCount() { 31 return TYPE_MAX_COUNT; 32 } 33 @Override 34 public int getCount() { 35 return datas.size(); 36 } 37 38 @Override 39 public Object getItem(int position) { 40 41 return datas.get(position); 42 } 43 44 @Override 45 public long getItemId(int position) { 46 47 return position; 48 } 49 50 @Override 51 public View getView(int position, View convertView, ViewGroup parent) { 52 View view=convertView; 53 int type=getItemViewType(position); 54 ViewHolder viewHolder=null; 55 ViewHolder1 viewHolder1=null; 56 if(view==null){ 57 if(type==TYPE_ITEM){ 58 59 view=mInflater.inflate(R.layout.item1, null); 60 viewHolder=new ViewHolder(); 61 viewHolder.textview1=(TextView) view.findViewById(R.id.title); 62 viewHolder.textview2=(TextView) view.findViewById(R.id.num); 63 view.setTag(viewHolder);//View中的setTag(Onbect)表示给View添加一个格外的数据,以后可以用getTag()将这个数据取出来。 64 }else{ 65 view=mInflater.inflate(R.layout.item2, null); 66 viewHolder1=new ViewHolder1(); 67 viewHolder1.textview1=(TextView)view.findViewById(R.id.title); 68 view.setTag(viewHolder1); 69 } 70 } 71 72 if(type==TYPE_ITEM){ 73 viewHolder=(ViewHolder) view.getTag(); 74 viewHolder.textview1.setText(datas.get(position).get("title")); 75 viewHolder.textview2.setText(datas.get(position).get("num")); 76 }else{ 77 viewHolder1=(ViewHolder1) view.getTag(); 78 viewHolder1.textview1.setText(datas.get(position).get("title")); 79 view.setBackgroundColor(Color.BLUE); 80 } 81 return view; 82 } 83 84 }
1 public static class ViewHolder{ 2 public TextView textview1; 3 public TextView textview2; 4 } 5 6 public static class ViewHolder1{ 7 public TextView textview1; 8 }
ViewHolder,ViewHolder1分别对应两种不同视图,一种item,一种分割栏
item1.xml
1 <LinearLayout 2 xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" 5 android:padding="10dip"> 6 7 <TextView 8 android:id="@+id/title" 9 android:layout_width="fill_parent" 10 android:layout_height="wrap_content" 11 android:gravity="left" 12 android:textSize="18sp" 13 android:layout_weight="1"/> 14 <TextView 15 android:id="@+id/num" 16 android:layout_width="fill_parent" 17 android:layout_height="wrap_content" 18 android:gravity="center_horizontal" 19 android:textSize="18sp" 20 android:layout_weight="1"/> 21 </LinearLayout>
item2.xml
1 <LinearLayout 2 xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent"> 5 6 <TextView 7 android:id="@+id/title" 8 android:gravity="left" 9 android:textSize="22sp" 10 android:background="#BCD2EE" 11 android:layout_width="fill_parent" 12 android:layout_height="wrap_content" 13 android:padding="5dip" 14 /> 15 16 </LinearLayout>
初始化数据
1 private void init(MyAdapter adapter){ 2 Map<String,String> map=null; 3 for(int i=0;i<100;i++){ 4 if(i%5!=0){ 5 map=new HashMap<String, String>(); 6 map.put("title", "title"+i); 7 map.put("num", "num"+i); 8 adapter.add(map); 9 }else{ 10 map=new HashMap<String, String>(); 11 map.put("title", "S"+i/5); 12 adapter.addSeparator(map); 13 } 14 } 15 }
显示效果