BaseAdapter 适配器,是我们经常使用的。可能一个项目中都有十几甚至几十个。细心的同学可能会发现,每一个适配器的结构基本相同,这就让我们想到了代码抽取。
BaseAdater 本身使用的就是适配器模式。相信大家对这种模式都很了解,所以今天就使用适配器模式对BaseAdapter 的代码进行抽取封装。接下来会对比普通写法和封装完之后的写法:
首先:通常的写法
ListView 的 item.xml 布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:padding="10dp"
android:text="姓名"
android:id="@+id/item_name_tv"
android:layout_width="match_parent"
android:layout_height="40dp" />
</LinearLayout>
public class MyAdapter extends BaseAdapter {
private Context mContext;
private List<String> mList;
public MyAdapter(Context mContext,List<String> mList) {
this.mContext=mContext;
this.mList=mList;
}
@Override
public int getCount() {
return mList != null ? mList.size() : 0;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return mList != null ? mList.get(position) : null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder=null;
if(convertView==null){
convertView=LayoutInflater.from(mContext).inflate(R.layout.item, parent,false);
holder=new ViewHolder(convertView);
convertView.setTag(holder);
}else{
holder=(ViewHolder)convertView.getTag();
}
holder.nameTv.setText("姓名:"+mList.get(position));
return convertView;
}
private class ViewHolder{
private TextView nameTv;
public ViewHolder(View view) {
if(view==null)
return;
nameTv=(TextView)view.findViewById(R.id.item_name_tv);
}
}
}
数据展示:
public class MainActivity extends Activity {
private ListView mListView;
private List<String> mList=new ArrayList<String>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView=(ListView)findViewById(R.id.listview);
getData();
MyAdapter adapter=new MyAdapter(this, mList);
mListView.setAdapter(adapter);
}
//获取数据
private void getData() {
for (int i = 0; i < 10; i++) {
mList.add("小明:"+i);
}
}
}
效果:这是常用的写法。但是适配器多了你会发现
@Override
public int getCount() {}
@Override
public Object getItem(int position) { }
@Override
public long getItemId(int position) {}
@Override
public View getView(int position, View convertView, ViewGroup parent) {}
这几个方法一直在不断的重复编写,这样写我是看不下去的。所以封装之路刻不容缓。
但是:要对试用多有的Adapter 需要解决以下问题
1、数据对象基本都不相同,不能写死
2、展示的View 布局基本不相同,不能写死
所以,这里就需要使用泛型
上代码:
AbsBaseAdapter.class
T 对象泛型 ; H ViewHolder 泛型
public abstract class AbsBaseAdapter<T,H extends AbsBaseAdapter.IViewHolder> extends BaseAdapter {
public Context mContext;
public List<T> mList;
private LayoutInflater mInflater;
private int layoutId;// 布局id
public AbsBaseAdapter(Context mContext,int layoutId) {
this.mContext = mContext;
this.layoutId=layoutId;
mInflater = LayoutInflater.from(mContext);
mList=new ArrayList<T>();
}
/**
* 设置数据
* */
public boolean addElements(List<T> mList) {
if (this.mList != null)
return this.mList.addAll(mList);
else
return false;
}
@Override
public int getCount() {
return mList != null ? mList.size() : 0;
}
@Override
public T getItem(int position) {
return mList != null ? mList.get(position) : null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
H holder = null;
if (convertView == null) {
convertView = mInflater.inflate(layoutId, parent, false);
holder = createViewHolder(convertView);
convertView.setTag(holder);
} else {
holder = (H) convertView.getTag();
}
convertView(mList.get(position), position, holder);
return convertView;
}
// 创建ViewHoler
public abstract H createViewHolder(View view);
// 给布局设置数据
public abstract void convertView(T bean,int position,H holder);
//所有 ViewHolder 都需要实现该接口
public interface IViewHolder{
}
}
然后让 MyAdapter 继承 AbsBaseAdapter 。
在看MyAdapter的代码 MyAdapter.class
public class MyAdapter extends AbsBaseAdapter<String, MyAdapter.ViewHolder> {
public MyAdapter(Context mContext) {
super(mContext, R.layout.item);
}
@Override
public ViewHolder createViewHolder(View view) {
return new ViewHolder(view);
}
@Override
public void convertView(String bean, int position, ViewHolder holder) {
holder.nameTv.setText("姓名:"+bean);
}
class ViewHolder implements AbsBaseAdapter.IViewHolder{
private TextView nameTv;
public ViewHolder(View view) {
if(view==null)
return;
nameTv=(TextView)view.findViewById(R.id.item_name_tv);
}
}
}
是不是非常的简洁,清晰!!!
然后 在Activity 中使用:
public class MainActivity extends Activity {
private ListView mListView;
private List<String> mList=new ArrayList<String>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView=(ListView)findViewById(R.id.listview);
getData();
MyAdapter adapter=new MyAdapter(this);
adapter.addElements(mList);
mListView.setAdapter(adapter);
}
//获取数据
private void getData() {
for (int i = 0; i < 10; i++) {
mList.add("小明:"+i);
}
}
}
以后再写Adapter 时,可以直接继承AbsAdapter 这个类。
你还可以在AbsAdapter 中继续扩展一些可能用到的方法。例如
/**
* 添加单个数据
*/
public boolean addElement(T bean) {
if (mList != null)
return mList.add(bean);
else
return false;
}
/**
* 添加数据到指定位置
*/
public void addElement(int position, T bean) {
if (mList != null)
mList.add(position, bean);
}
/**
* 根据position添加数据
*/
public boolean addElements(int position, List<T> mList) {
if (this.mList != null)
return this.mList.addAll(position, mList);
else
return false;
}
/**
* 根据postion 删除数据
*/
public T removeElement(int position) {
if (mList != null)
return mList.remove(position);
else
return null;
}
/**
* 删除
*/
public boolean removeElement(T bean) {
if (mList != null)
return mList.remove(bean);
else
return false;
}