在Adapter在开发中使用到的地方很多,经常是与ListView搭配使用,下面是android中adapter的继承结构,A:abstractClass、I:interface、C:class.
(这边的图,我在有道云笔记上面画的,但是CSDN貌似不识别这个语法,就截图出来了)
下面详细介绍每一种adapter的用法:
首先是具体实现类的使用
这类adapter用法简单,有现成的构造方法,我们只需要传入相应的参数,就可以很轻松的使用了。
1. ArrayAdapter
ArrayList<String> array = new ArrayList<String>();
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.base_adapter, R.id.textView, array);
下面是base_adapter.xml的内容:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
2.SimpleAdapter
List<Map<String,Object>> data = new ArrayList<Map<String,Object>>();
Map<String,Object> data1 = new HashMap<String,Object>();
data1.put("text", "first");
data1.put("icon", R.drawable.ic_launcher);
Map<String,Object> data2 = new HashMap<String,Object>();
data2.put("text", "second");
data2.put("icon", R.drawable.ic_launcher);
data.add(data1);
data.add(data2);
listView = (ListView)this.findViewById(R.id.myList);
SimpleAdapter adapter = new SimpleAdapter(this, data, R.layout.simple_adapter,
new String[]{"text","icon"}, new int[]{R.id.textView,R.id.imageView});
listView.setAdapter(adapter);
下面是 simple_adapter 的布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/imageView"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
/>
</LinearLayout>
下面是效果图:
3.SimpleCursorAdapter
看名字就知道了,数据源provider
Cursor cursor = getContentResolver().query(Phone.CONTENT_URI,
new String[]{Phone._ID,Phone.NUMBER,Phone.DISPLAY_NAME},
null, null, null);
SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter(this, R.layout.simple_adapter,
cursor, new String[]{Phone.DISPLAY_NAME,Phone.NUMBER},
new int[]{R.id.name,R.id.number},0x02);
listView.setAdapter(cursorAdapter);
simple_adapter.xml的布局就不写了,就是两个TextVIew 。这边需要注意一点的就是,当cursor的内容设给adapter时,一定要有”_id”这一列。 这段代码读取了手机联系人的姓名和号码,效果如下:
以上的adapter是android帮我们实现好的,使用非常简单。但是listView中内容格式是完全一致的,如果想要实现差异化,那么就需要实现自己的adapter了。
自定义adapter
其实所谓的自定义adapter,就是去继承BaseAdapter和CursorAdapter啦
1.BaseAdapter
当我们继承BaseAdapter时,IDE会贴心的告诉我们需要复写下面的方法:getCount()、getItem(int position)、getItemId(int position)、getView(int position, View convertView, ViewGroup parent),我们来看一下SimpleAdapte中这几个方法的实现来了解一下这些方法的作用:
private List<? extends Map<String, ?>> mData;
public SimpleAdapter(Context context, List<? extends Map<String, ?>> data,
@LayoutRes int resource, String[] from, @IdRes int[] to) {
mData = data;
mResource = mDropDownResource = resource;
...
}
/**
* @see android.widget.Adapter#getCount()
*/
public int getCount() {
return mData.size();
}
/**
* @see android.widget.Adapter#getItem(int)
*/
public Object getItem(int position) {
return mData.get(position);
}
/**
* @see android.widget.Adapter#getItemId(int)
*/
public long getItemId(int position) {
return position;
}
/**
* @see android.widget.Adapter#getView(int, View, ViewGroup)
*/
public View getView(int position, View convertView, ViewGroup parent) {
return createViewFromResource(mInflater, position, convertView, parent, mResource);
}
private View createViewFromResource(LayoutInflater inflater, int position, View convertView,
ViewGroup parent, int resource) {
View v;
if (convertView == null) {
v = inflater.inflate(resource, parent, false);
} else {
v = convertView;
}
bindView(position, v);
return v;
}
首先看getCount(),他返回的是adapter中内容的数量;
再看getView()方法,他调用了inflater.inflate(resource, parent, false);加载了我们在构造SimpleAdapter时传入的布局ID;
再来看getItem(),返回的就是adapter的内容啦;getItemId()就是listView中位置对应在adapter数据的位置,这边返回的就是listView的位置,因为基本上adapter总的内容在填充一个listView时,位置肯定就是一一对应的啦。
我们现在来实现一个这样的adapter,它包含一个textView和一个checkBox,但是要求这个CheckBox显示出来是随机的,先看布局,很简单:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<CheckBox
android:id="@+id/checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
再来看adapter的实现:
public class MyBaseAdapter extends BaseAdapter {
private final LayoutInflater mLayoutInflater;
private List<String> list;
private Context mContext;
public MyBaseAdapter(Context context,ArrayList<String> arrayList){
mLayoutInflater = LayoutInflater.from(context);
list = arrayList;
mContext = context;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
if(list!=null){
return list.size();
}else{
return 0;
}
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
LinearLayout view = null;
if (convertView != null) {
view = (LinearLayout)convertView;
} else {
view = (LinearLayout)mLayoutInflater.inflate(R.layout.simple_adapter, parent,false);
}
TextView tv = (TextView)view.findViewById(R.id.textView);
tv.setText(list.get(position));
CheckBox check = (CheckBox)view.findViewById(R.id.checkBox);
Random random = new Random();
boolean show = random.nextBoolean();
if(show){
check.setVisibility(View.VISIBLE);
}else{
check.setVisibility(View.GONE);
}
return view;
}
}
最后在activity中使用一下:
ArrayList<String> array = new ArrayList<String>();
array.add("aaaa");
array.add("bbbb");
array.add("cccc");
array.add("dddd");
array.add("eeee");
array.add("ffff");
array.add("gggg");
array.add("hhhh");
array.add("iiii");
listView.setAdapter(new MyBaseAdapter(this,array));
最终看下效果图
2.CursorAdapter
继承这个类只需要实现两个方法,就是newView()和bindView,当然还得实现的就是构造方法,好把cursor往上传,让getCount()方法能够得到正确的返回值。
其实newView()和bindView(),在两个方法都会在getView()中调用,getView()方法在每绘制一个数据时,都会被执行,不管之前有木有绘制过,也就是说如果我们来回滑动listView,那么getView()方法一直会被调用。但是我们来看一下CursorAdapter中的getView()方法
View v;
if (convertView == null) {
v = newView(mContext, mCursor, parent);
} else {
v = convertView;
}
bindView(v, mContext, mCursor);
就很容易会发现,只要这个View创建好了,newView()就不会再调用啦,反应到我们的adapter中就是,adapter有多少个数据,就会调用多少个newView(),但是每绘制一个view,都会调用bindView。
下面是一个小的例子:
首先布局就不写了,只有两个TextView
然后要继承CursorAdapter
public class MyCursorAdapter extends CursorAdapter {
private LayoutInflater inflater;
private Cursor cursor;
public MyCursorAdapter(Context context, Cursor c, boolean autoRequery) {
super(context, c, autoRequery);
inflater = LayoutInflater.from(context);
cursor = c;
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return inflater.inflate(R.layout.simple_adapter, parent, false);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView name = (TextView)view.findViewById(R.id.name);
TextView number = (TextView)view.findViewById(R.id.number);
name.setText(cursor.getString(1));
number.setText(cursor.getString(2));
}
}
在activity中使用一下:
Cursor cursor = this.getContentResolver().query(Phone.CONTENT_URI,
new String[]{Phone._ID,Phone.DISPLAY_NAME,Phone.NUMBER},
null,null,null);
MyCursorAdapter adapter = new MyCursorAdapter(this,cursor,false);
listView.setAdapter(adapter);
最后一张效果图:
可以看到跟SimpleACursorAdapter一样,但是实现完全不同啦。