Adapter的继承结构

Adapter的继承结构

Adapter的继承结构

Adapter的作用

Adapter是AdapterView视图与数据之间的桥梁,Adapter提供对数据的访问,也负责为每一项数据产生一个对应的View。其作用如下图所示:

Adapter的继承结构

各个类的作用

 

Adapter

Adapter做为这个继承结构的最顶层的基接口,定义了Adapter要实现的基本方法:

1
2
3
4
4
5
6
7
7
8
9
10
11
12
13
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public  interface  Adapter {
     //注册一个Observer,当Adapter所表示的数据改变时会通知它,DataSetObserver是一个抽象类,定义了两个方法:onChanged与onInvalidated
     void  registerDataSetObserver(DataSetObserver observer);
     //取消注册一个Observer
     void  unregisterDataSetObserver(DataSetObserver observer);
     //所表示的数据的项数
     int  getCount();
     //返回指定位置的数据项
     Object getItem( int  position);
     //返回指定位置的数据项的ID
     long  getItemId( int  position);
     //表示所有数据项的ID是否是稳定的,在BaseAdapter中默认返回了false,假设是不稳定的,在CursorAdapter中返回了true,Cursor中的_ID是不变的
     boolean  hasStableIds();
     //为每一个数据项产生相应的视图
     View getView( int  position, View convertView, ViewGroup parent);
     //为了避免产生大量的View浪费内存,在Android中,AdapterView中的View是可回收的使用的。比如你有100项数据要显示,而你的屏幕一次只能显示10条数据,则
     //只产生10个View,当往下拖动要显示第11个View时,会把第1个View的引用传递过去,更新里面的数据再显示,也就是说View可重用,只是更新视图中的数据用于显示新
     //的一项,如果一个视图的视图类型是IGNORE_ITEM_VIEW_TYPE的话,则此视图不会被重用
     static  final  int  IGNORE_ITEM_VIEW_TYPE = AdapterView.ITEM_VIEW_TYPE_IGNORE;
     //获得相应位置的这图类型
     int  getItemViewType( int  position);
     //getView可以返回的View的类型数量。(在HeaderViewListAdapter中可以包含Header和Footer,getView可以返回Header、Footer及Adapter
     //中的视图,但其getViewTypeCount的实现只是调用了内部Adapter的的getViewTypeCount,忽略了Header、Footer中的View Type,不懂。
     int  getViewTypeCount();
     static  final  int  NO_SELECTION = Integer.MIN_VALUE;
     boolean  isEmpty();
}

Adapter有两个子接口,ListAdapter(列表)与SpinnerAdapter(下拉列表),它们都只定义了少数方法。一般除WrapperListAdapter接口及其实现类只实现了ListAdapter外,都同时实现了这两个接口。

ListAdapter

1
2
3
4
//是否在ListAdapter中的所有项都enabled,即是否所有项都selectable和clickable
public  boolean  areAllItemsEnabled();
//指定位置的项是否是enabled的
boolean  isEnabled( int  position);

SpinnerAdapter

1
2
//产生相应位置下拉项的视图
public  View getDropDownView( int  position, View convertView, ViewGroup parent);

BaseAdapter

1
一个抽象类,Adapter的基础实现类,一般作为其他实现类的基类,同时实现ListAdapter与SpinnerAdapter,提供了一些方法的默认实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public  abstract  class  BaseAdapter implements  ListAdapter, SpinnerAdapter {
     //提供一些方法,当数据改变时调用注册的DataSetObserver的回调函数
     private  final  DataSetObservable mDataSetObservable = new  DataSetObservable();
     public  boolean  hasStableIds() {
         return  false ;
     }
     public  void  registerDataSetObserver(DataSetObserver observer) {
         mDataSetObservable.registerObserver(observer);
     }
     public  void  unregisterDataSetObserver(DataSetObserver observer) {
         mDataSetObservable.unregisterObserver(observer);
     }
     //通知相关联的视图,相应的数据已经改变
     public  void  notifyDataSetChanged() {
         mDataSetObservable.notifyChanged();
     }
     public  void  notifyDataSetInvalidated() {
         mDataSetObservable.notifyInvalidated();
     }
     public  boolean  areAllItemsEnabled() {
         return  true ;
     }
     public  boolean  isEnabled( int  position) {
         return  true ;
     }
     //通过getView实现
     public  View getDropDownView( int  position, View convertView, ViewGroup parent) {
         return  getView(position, convertView, parent);
     }
     public  int  getItemViewType( int  position) {
         return  0 ;
     }
     public  int  getViewTypeCount() {
         return  1 ;
     }
     public  boolean  isEmpty() {
         return  getCount() == 0 ;
     }
}

ArrayAdapter<T>

1
以下是SDK的说明:

A concrete BaseAdapter that is backed by an array of arbitrary objects. By default this class expects that the provided resource id references a single TextView. If you want to use a more complex layout, use the constructors that also takes a field id. That field id should reference a TextView in the larger layout resource.

However the TextView is referenced, it will be filled with the toString() of each object in the array. You can add lists or arrays of custom objects. Override the toString() method of your objects to determine what text will be displayed for the item in the list.

To use something other than TextViews for the array display, for instance, ImageViews, or to have some of data besides toString() results fill the views, override getView() to return the type of view you want.

 

默认ArrayAdapter产生的视图期望一个TextView,或者也可以指定一个Layout并指定其中一个类型为TextView的资源的ID,其底下的数据可以是任意类型,但显示的时候会调用其toString()方法,也就是说只能用TextView显示文字,如果想显示其他的数据,要重写getView()

ArrayAdapter有5个构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public  ArrayAdapter(Context context, int  textViewResourceId) {
     init(context, textViewResourceId, 0 , new  ArrayList<T>());
}
public  ArrayAdapter(Context context, int  resource, int  textViewResourceId) {
     init(context, resource, textViewResourceId, new  ArrayList<T>());
}
public  ArrayAdapter(Context context, int  textViewResourceId, T[] objects) {
     init(context, textViewResourceId, 0 , Arrays.asList(objects));
}
public  ArrayAdapter(Context context, int  resource, int  textViewResourceId, T[] objects) {
     init(context, resource, textViewResourceId, Arrays.asList(objects));
}
public  ArrayAdapter(Context context, int  textViewResourceId, List<T> objects) {
     init(context, textViewResourceId, 0 , objects);
}
public  ArrayAdapter(Context context, int  resource, int  textViewResourceId, List<T> objects) {
     init(context, resource, textViewResourceId, objects);
}

 

最多有4个参数,分别为当前Context,layout(可省),TextView的ID与数据(可为数组或List),在构造函数中都调用了一个叫init的函数

1
2
3
4
5
6
7
private  void  init(Context context, int  resource, int  textViewResourceId, List<T> objects) {
        mContext = context;
        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mResource = mDropDownResource = resource;
        mObjects = objects;
        mFieldId = textViewResourceId;
    }

分别赋值给类中的私有域,mInflater为LayoutInflater,产生相应项的视图。

类中有两个域保存数据

1
2
private  ArrayList<T> mOriginalValues;
private  List<T> mObjects;

其中mOriginalValues用于过滤数据时保存过滤前的数据,将过滤后的数据存入mObjects。

在ArrayAdapter中还定义了add,insert,remove,clear函数用于改变数据,并定义了一个布尔变量mNotifyChange用于表示用这些函数改变数据后是否通知视图(调用notifyDataSetChanged,调用这个函数时会把mNotifyChange置为true。

一些函数的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public  int  getCount() {
     return  mObjects.size();
}
public  T getItem( int  position) {
     return  mObjects.get(position);
}
public  int  getPosition(T item) {
     return  mObjects.indexOf(item);
}
public  long  getItemId( int  position) {
     return  position;
}
public  View getView( int  position, View convertView, ViewGroup parent) {
     return  createViewFromResource(position, convertView, parent, mResource);
}
public  View getDropDownView( int  position, View convertView, ViewGroup parent) {
     return  createViewFromResource(position, convertView, parent, mDropDownResource);
}
1
可以看到getView和getDropDownView都通过调用createViewFromResourse来产生视图。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
private  View createViewFromResource( int  position, View convertView, ViewGroup parent,
            int  resource) {
        View view;
        TextView text;
 
        if  (convertView == null ) {
            view = mInflater.inflate(resource, parent, false );
        } else  {
            view = convertView;
        }
 
        try  {
            if  (mFieldId == 0 ) {
                //  If no custom field is assigned, assume the whole resource is a TextView
                text = (TextView) view;
            } else  {
                //  Otherwise, find the TextView field within the layout
                text = (TextView) view.findViewById(mFieldId);
            }
        } catch  (ClassCastException e) {
            Log.e( "ArrayAdapter" , "You must supply a resource ID for a TextView" );
            throw  new  IllegalStateException(
                    "ArrayAdapter requires the resource ID to be a TextView" , e);
        }
 
        T item = getItem(position);
        if  (item instanceof  CharSequence) {
            text.setText((CharSequence)item);
        } else  {
            text.setText(item.toString());
        }
 
        return  view;
    }

 

在createViewFromResource中,首先判断convertView是否存在,若不存在则inflate一个,然后判断mFieldID是否为0,若为0则表示传递给ArrayAdapter的资源ID为一TextView,否则是传递了一Layout,mFieldID为此Layout中TextView的ID。然后通过getItem取得相应位置的数据项,判断是否是CharSequence的实例,如果是直接setText,否则调用其toString()函数,可以ArrayAdapter默认只能给TextVext设置字符串,若要使用其他视图,需要重载getView或getDropDownView,一般情况下会继承BaseAdapter自定义自己的Adapter。

在ArrayAdapter中,还有一静态函数

1
2
3
4
5
public  static  ArrayAdapter<CharSequence> createFromResource(Context context,
             int  textArrayResId, int  textViewResId) {
         CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
         return  new  ArrayAdapter<CharSequence>(context, textViewResId, strings);
     }

 

读取资源文件中定义的字符数组作为数据生成ArrayAdapter,可以看到只能用TextView视图,而不可以指定一Layout再指定Layout中一个TextView的ID。

在ArrayAdapter中还定义了一个ArrayFilter,继承自Filter,用于过滤数据项(当ListView有焦点时,通过键盘输入字符来进行列表项的过滤),其过滤方法为传入一CharSequence,判断相应数据项是否以此CharSequence开头,若不是则用空格分割些数据项,判断分割后的各字符串是否以此CharSequence开头,若是则保留(若数据不是CharSequence则调用其toString())。如果传入的CharSequence为null或长度为0则不过滤。

CursorAdapter

用于显示Cursor中的数据。

在构造函数中可传递一参数autoRequery表示当cursor的数据改变时是否自动调用cursor的requery()以保持视图数据为最新的。

此类中重写了hasStableIds(),返回true。

1
2
3
public  boolean  hasStableIds() {
     return  true ;
}
1
在CursorAdapter中,重写的getView及getDropDownView判断传入的convertView是否为 null ,若为 null 及相应地调用newView()或newDropDownView()来生成一个视图,而newDropDownView()只有一条语句 return  newView(context, cursor, parent);所以最后都是调用newView(),newView()为 abstract 的,需要由子类重写。
1
当通过newView()产生一个View之后,会调用 bindView(v, mContext, mCursor);将cursor中的数据绑定到newView()产生的View之中,此方法同样为 abstract 的。
1
CursorAdapter实现了接口CursorFilter.CursorFilterClient中的方法
1
2
3
4
5
6
//改变cursor指向的数据
public  void  changeCursor(Cursor cursor)
//将cursor转变为CharSequence,返回""或调用cursor.toString()
public  CharSequence convertToString(Cursor cursor)
//过滤数据
public  Cursor runQueryOnBackgroundThread(CharSequence constraint)

ResourceCursorAdapter

如类名所示,该类继承自CursorAdapter,通过XML产生Views,该类只是简单地重写了一些函数,通过LayoutInflater.inflate将XML转换为View

1
2
3
4
5
6
7
8
9
@Override
public  View newView(Context context, Cursor cursor, ViewGroup parent) {
     return  mInflater.inflate(mLayout, parent, false );
}
 
@Override
public  View newDropDownView(Context context, Cursor cursor, ViewGroup parent) {
     return  mInflater.inflate(mDropDownLayout, parent, false );
}

SimpleCursorAdapter

一个ResourceCursorAdapter的简单实现类,用于把cursor中相应的列映射为XML定义的视图中的TextView和ImageView。

该类中定义了一个接口

1
2
3
public  static  interface  ViewBinder {
     boolean  setViewValue(View view, Cursor cursor, int  columnIndex);
}

用于设置把cursor中的列映射为视图的方法。

在SimpleCursorAdapter中重写了bindView,控制cursor到视图的绑定,其定义如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Override
     public  void  bindView(View view, Context context, Cursor cursor) {
         final  ViewBinder binder = mViewBinder;
         final  int  count = mTo.length;
         final  int [] from = mFrom;
         final  int [] to = mTo;
 
         for  ( int  i = 0 ; i < count; i++) {
             final  View v = view.findViewById(to[i]);
             if  (v != null ) {
                 boolean  bound = false ;
                 if  (binder != null ) {
                     bound = binder.setViewValue(v, cursor, from[i]);
                 }
 
                 if  (!bound) {
                     String text = cursor.getString(from[i]);
                     if  (text == null ) {
                         text = "" ;
                     }
 
                     if  (v instanceof  TextView) {
                         setViewText((TextView) v, text);
                     } else  if  (v instanceof  ImageView) {
                         setViewImage((ImageView) v, text);
                     } else  {
                         throw  new  IllegalStateException(v.getClass().getName() + " is not a "  +
                                 " view that can be bounds by this SimpleCursorAdapter" );
                     }
                 }
             }
         }
     }

可以看到,首先检查类中的私有域mViewBinder是否为null(默认为null,可通过setViewBinder)设置,为不为null则通过binder.setViewValue(v, cursor, from[i]); 进行绑定,这个函数若返回true则绑定成功,若返回false则通过SimpleCursorAdapter的规则绑定,判断相应的View是否为TextView或ImageView,若是则绑定,否则抛出异常。

由些可以看到,我们可以自定义一个类实现SimpleCursorAdapter.ViewBinder,然后通过setViewBinder来改变bindView的结果。

SimpleAdapter

一个BaseAdapter的实现类,用于绑定数据到一个XML定义的视图中。数据类型为ArrayList<Map<String, ?>>。

SimpleAdapter也实现了Filter接口用于数据的过滤,过滤方法类似ArrayAdapter,只是其数据类型为Map<String,?>,要判断Map中的每一项,若任意一顶符合要求就保留。

SimpleAdapter也是通过bindView函数进行数据的绑定,同SimpleCursorAdapter一样,SimpleAdapter也定义了一个相同的内部接口ViewBinder,在bindView中,首先判断是否通过setViewBinder设置了ViewBinder,若设置了则调用其setViewValue进行数据绑定,如果没有设置其setViewValue返回了false,则进行下面的处理:依次判断View是否为Checkable,TextView,ImageView并进行相应的处理,可见默认情况下SimpleAdapter也是处理TextView与ImageView,当然可以setViewBinder。

WrapperListAdapter

继承自ListAdapder的接口,所以也是一个ListAdapter,同时里面嵌入了另一个ListAdapter,只定义了一个函数用于取得嵌入的ListAdapter

1
public  ListAdapter getWrappedAdapter();

HeaderViewListAdapter

继承自WrapperListAdapter,当你使用的ListView有页首(Header Views)或页尾(Footer Views)时使用。此类被设计用来作为一个基类,一般不需要使用,当对一个ListView调用addHeaderView时会被自动转换为HeaderViewListAdapter,所以用ListAdapter时要注意,其类型可能会改变。

类中定义了两个ArrayList用于保存页首和页尾

1
2
ArrayList<ListView.FixedViewInfo> mHeaderViewInfos;
ArrayList<ListView.FixedViewInfo> mFooterViewInfos;

这两个域不为null,在构造函数中判断,如果给这两个域赋值的参数为null,则将他们赋于值 HeaderViewListAdapter.EMPTY_INFO_LIST,其定义为

1
2
static  final  ArrayList<ListView.FixedViewInfo> EMPTY_INFO_LIST =
         new  ArrayList<ListView.FixedViewInfo>();

 

其中ListView.FixedViewInfo的定义为

1
2
3
4
5
public  class  FixedViewInfo {
     public  View view;ListAdapter#getItem( int )}.
     public  Object data;
<code class="java spaces" style="white-space: pre-wrap; margin: 0px !important; padding: 0px !important; border-top-left-radius: 0px !important; border-top-right-radius: 0px !important; border-bottom-right-radius: 0px !important; border-bottom-left-radius: 0px !important; background-image: none !important;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值