简略的介绍下ViewHolder的实现,谷歌很聪明的在Adapter中运用了复用View的思想,自然让我们的屌丝机也能泡上一些白富美应用多了一点点可能。ViewHolder的具体实现基本体现在BaseAdapter的 getView(int position, View convertView, ViewGroup parent) 这个方法里面,参见下面的代码:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.listview_item_layout, parent, false);
holder = new ViewHolder();
holder.studentName = (TextView) convertView.findViewById(R.id.student_name);
holder.studentAge = (TextView) convertView.findViewById(R.id.student_age);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
Student data = (Student) getItem(position);
holder.studentName.setText(data.getName());
holder.studentAge.setText(data.getAge());
return convertView;
}
class ViewHolder {
public TextView studentName;
public TextView studentAge;
}
很明显,大家不要问我ViewHolder在哪里,稍微把目光往上扶一扶就看到那个大大的 class ViewHolder 。这里的ViewHolder用法主要有两个地方,一是 convertView 的复用,二是 ViewHolder 也就是 convertView 里面的索引的复用。具体的用法不熟悉的话可以百度一下,再往下说就对不起我今天这篇博文了,因为在这里写这个代码的目的,肯定不是介绍你怎么用ViewHolder,只是想告诉你:传统的ViewHolder的写法,是多么的臃肿!而且对于每一个新的BaseAdapter,你都得无聊的实现一次又一次.
ViewHolder的工具类实现
自然,脱光要从小,行动要趁早。既然我们烦了,就把它写成一个工具类咯。参见下面的代码
static class ViewHolder {
public static <T extends View> T get(View view, int id) {
SparseArray<View> viewHolder = (SparseArray<View>) view.getTag();
if (viewHolder == null) {
viewHolder = new SparseArray<View>();
view.setTag(viewHolder);
}
View childView = viewHolder.get(id);
if (childView == null) {
childView = view.findViewById(id);
viewHolder.put(id, childView);
}
return (T) childView;
}
}
这是工具类的实现,稍微说下实现的原理:
1、ViewHolder既然是依赖View的Tag存放,但是以一个 SparseArray 集合存放。
2、判断View里的Tag是否存在viewHolder,不存在,赶紧叫她生一个。
3、然后在viewholder(也就是SparseArray)寻找View的索引,如果没有,赶紧findViewById一个put进去顺便return出来,如果已经存在,皆大欢喜,直接用呗。
贴个BaseAdapter里面使用的代码:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.listview_item_layout, parent, false);
}
TextView name = Tools.ViewHolder.get(convertView, R.id.student_name);
TextView age = Tools.ViewHolder.get(convertView, R.id.student_age);
Student data = (Student) getItem(position);
name.setText(data.getName());
age.setText(data.getAge());
return convertView;
}
简洁明了,不用多说~~~嘿嘿,后面如果要写ViewHolder,直接Tools工具类调用,省心不废脑。。
分析可行性
既然要作为工具类使用,我们有必要先评估这个工具值不值得我们使用。
一般来说,我们可以从以下几个方面进行评估:易用性? 内存泄露? 性能提升? 健壮性?等等等。。。。。。
易用性:工具类的最大特性就是易用简约,这个ViewHolder的写法就是典型的拿来就用的主义,根本不用我们操心写些适配的代码,直接传入View和id,高内聚松耦合。并且采用了 T的泛型模板的方法,自动与外部的View子类适配,不用我们手动去强制装换。
内存泄露:有些初学者,看到static方法就回固执的认为 SparseArray viewHolder 这个变量会存在内存泄露,但是java告诉我们,这个变量的小命仅仅在方法执行之中,方法完毕,GC回收;存在ViewHolder一如既往放在View的Tag中,一旦View被回收,ViewHolder自然消失。不信,打开DDMS,用你28青年的手速不停刷listView试试,保证对象基本稳定在一个值。
性能提升:在这里我们发现用了 SparseArray 这个集合而不是 HashMap ,我们知道 SparseArray 是Android的一个工具类,是官方推荐用来代替 HashMap