标签:
public class SimpleAdapter extends BaseAdapter { public static class ViewHolder { public TextView tvName; } private List<Student> studentList; private LayoutInflater inflater; public SimpleAdapter(Context context, List<Student> students) { inflater = LayoutInflater.from(context); this.studentList = students; } @Override public int getCount() { return studentList.size(); } @Override public Student getItem(int position) { return studentList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; View view = convertView; if (view == null) { view = inflater.inflate(android.R.layout.simple_list_item_1, parent, false); holder = new ViewHolder(); holder.tvName = (TextView) view.findViewById(android.R.id.text1); view.setTag(holder); } else { holder = (ViewHolder) view.getTag(); } Student student = getItem(position); holder.tvName.setText(student.naem); return view; } }
Activity中调用
setListAdapter(new SimpleAdapter(getContext(),datas));这段代码应该不陌生,当继承BaseAdapter,必须重写getCount、getItem、getItemId、getView这4个方法,然后写一个构造方法传入实体对象。可以说你再写一个BaseAdapter也是同样的写法,仔细的你应该会发现,只有构造方法实体对象与getView中方法体业务逻辑有差异嘛,那么是不是可以把实体对象改写成泛型,getView方法体业务逻辑抽象出来,在外实现呢?那是必须可以的,接下来我们一步一步改善这要命的重复代码。
public class CygAdapter<T> extends BaseAdapter {//变化 public static class ViewHolder { public TextView tvName; } private List<T> studentList;//变化 private LayoutInflater inflater; public CygAdapter(Context context, List<T> students) { inflater = LayoutInflater.from(context); this.studentList = students; } @Override public int getCount() { return studentList.size(); } @Override public T getItem(int position) {//变化 return studentList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; View view = convertView; if (view == null) { view = inflater.inflate(android.R.layout.simple_list_item_1, parent, false); holder = new ViewHolder(); holder.tvName = (TextView) view.findViewById(android.R.id.text1); view.setTag(holder); } else { holder = (ViewHolder) view.getTag(); } T student = getItem(position);//变化 holder.tvName.setText(student.naem);//这里出问题咯,这个T泛型类根本就没有name变量嘛,怎么办? return view; } }上面代码已成功把实体对象改成了泛型,但是getView中的业务逻辑这时出现了上面代码中的问题,无法取到name变量,难道给Student实体类加注解?对于一个Student类注解是行得通滴,加一个@name注解嘛,但是又来一个学校School类、班级Class类那岂不是加N个不同命名的注解?这样一来加注解方案肯定就走不下去了。那么我们可以尝试把getView的业务逻辑抽象出来在外部实现,那现在就需要一个抽象方法了。
我们再CygAdapter改造一下,新建一个抽象方法 onBindData(ViewHolder viewHolder, final T item, final int position);
@Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; View view = convertView; if (view == null) { view = inflater.inflate(android.R.layout.simple_list_item_1, parent, false); holder = new ViewHolder(); holder.tvName = (TextView) view.findViewById(android.R.id.text1); view.setTag(holder); } else { holder = (ViewHolder) view.getTag(); } T student = getItem(position); //holder.tvName.setText(student.naem);//这里出问题咯,怎么办? onBindData(holder,student,position);//把上面holder.tvName.setText(student.naem)抽象到外部实现 return view; } //新建抽象方法 public abstract void onBindData(ViewHolder viewHolder, final T item, final int position);再来看在Activity中用法
setListAdapter(new com.mylhyl.cygadapter.sample.blog.CygAdapter<Student>(getContext(),datas) { @Override public void onBindData(ViewHolder viewHolder, Student item, int position) { viewHolder.tvName.setText(item.naem); } });
ArrayList<School> datas = new ArrayList(); datas.add(new School("珠海北师大")); datas.add(new School("长沙湖南大学")); setListAdapter(new com.mylhyl.cygadapter.sample.blog.CygAdapter<School>(getContext(), datas) { @Override public void onBindData(ViewHolder viewHolder, School item, int position) { viewHolder.tvName.setText(item.address); } });
ArrayList<Student> datas = new ArrayList(); datas.add(new Student(21,"张三")); datas.add(new Student(22,"李四")); setListAdapter(new com.mylhyl.cygadapter.sample.blog.CygAdapter<Student>(getContext(), datas) { @Override public void onBindData(ViewHolder viewHolder, Student item, int position) { viewHolder.tvName.setText(item.naem); viewHolder.tvAge.setText(String.valueOf(item.age));//尼玛没有ViewHolder中没有tvAge呀 } });上面代码ViewHolder中没有tvAge呀,新建一个不就得了,这样肯定是不行的,与刚才说的加注解方案一样的道理,ViewHolder中的变量只会越来越多,怎么办呢?竟然问题出现在ViewHolder就得从他来下手,我们看getView中的那段ViewHolder相关的代码
没有加age之前
ViewHolder holder; View view = convertView; if (view == null) { view = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);//一个TextView holder = new ViewHolder(); holder.tvName = (TextView) view.findViewById(android.R.id.text1);//名字 view.setTag(holder); } else { holder = (ViewHolder) view.getTag(); }加age之后
ViewHolder holder; View view = convertView; if (view == null) { view = inflater.inflate(android.R.layout.simple_list_item_2, parent, false);//二个TextView holder = new ViewHolder(); holder.tvName = (TextView) view.findViewById(android.R.id.text1);//名字 holder.tvAge = (TextView) view.findViewById(android.R.id.text2);//年龄 view.setTag(holder); } else { holder = (ViewHolder) view.getTag(); }上面代码是不是看出点什么呢?是不是除了inflate与findViewById部分不一样,那是不是有点思路了?新建一个类抽出相同部分,写成一个通用的ViewHolder,开干吧!
public final class CygViewHolder { private Context mContext; private View mItemView; public static CygViewHolder get(Context context, int resource, View convertView, ViewGroup parent) { if (convertView == null) { View view = LayoutInflater.from(context).inflate(resource, parent, false); return new CygViewHolder(context, view); } return (CygViewHolder) convertView.getTag(); } private CygViewHolder(Context context, View itemView) { mContext = context; mItemView = itemView; mItemView.setTag(this); } public View getItemView() { return mItemView; } }CygAdapter
@Override public View getView(int position, View convertView, ViewGroup parent) { //没有了一堆重复代码 CygViewHolder viewHolder = CygViewHolder.get(context, resource, convertView, parent); T student = getItem(position); onBindData(viewHolder, student, position); return viewHolder.getItemView(); } //ViewHolder改为CygViewHolder public abstract void onBindData(CygViewHolder viewHolder, final T item, final int position);ListView绑定CygAdapter的时候出现问题了,无法查找控件
ArrayList<Student> datas = new ArrayList(); datas.add(new Student(21,"张三")); datas.add(new Student(22,"李四")); setListAdapter(new com.mylhyl.cygadapter.sample.blog.CygAdapter<Student>(getContext(), datas) { @Override public void onBindData(CygViewHolder viewHolder, Student item, int position) { //查找TextView,还是没有tvName\tvAge?又得如何处理,想个办法 viewHolder.tvName = (TextView) view.findViewById(android.R.id.text1); viewHolder.tvAge = (TextView) view.findViewById(android.R.id.text2); //为TextView设置数据 viewHolder.tvName.setText(item.naem); viewHolder.tvAge.setText(String.valueOf(item.age)); } });上面代码onBindData绑定数据代码段的问题如何处理呢?思路是这样,既然CygViewHolder中已经有了每个Item的View,那么我们可以在CygViewHolder写个findViewById方法查找控件,并缓存在SparseArray<View>中,如果有直接从缓存中返回,否则通过itemView.findViewById查找,缓存再返回。
public final class CygViewHolder { private Context mContext; private SparseArray<View> mViews;//变化 private View mItemView; public static CygViewHolder get(Context context, int resource, View convertView, ViewGroup parent) { if (convertView == null) { View view = LayoutInflater.from(context).inflate(resource, parent, false); return new CygViewHolder(context, view); } return (CygViewHolder) convertView.getTag(); } private CygViewHolder(Context context, View itemView) { mContext = context; mViews = new SparseArray<>();//变化 mItemView = itemView; mItemView.setTag(this); } public <T extends View> T findViewById(int id) {//新增方法 View view = mViews.get(id); if (view == null) { view = mItemView.findViewById(id); mViews.put(id, view); } return (T) view; } }
使用
ArrayList<Student> datas = new ArrayList(); datas.add(new Student(21, "张三")); datas.add(new Student(22, "李四")); setListAdapter(new com.mylhyl.cygadapter.sample.blog.CygAdapter<Student> (getContext(), android.R.layout.simple_list_item_2, datas) { @Override public void onBindData(CygViewHolder viewHolder, Student item, int position) { TextView tvName = viewHolder.findViewById(android.R.id.text1); TextView tvAge = viewHolder.findViewById(android.R.id.text2); tvName.setText(item.naem); tvAge.setText(String.valueOf(item.age)); } });
说明一下CygViewHolder中我只加入了TextView.setText的方法,如有需要增加其它方法可以加Q群:435173211
也可到GitHub先fork后再new pull request 可者Issues
Android 通用ListView、GridView适配器
标签:
原文地址:http://blog.csdn.net/hupei/article/details/51906060