Android分类适配
访问密码 9b16
更新:
1.放弃使用键值来判断tag的方式,使用listview本身提供的方式。
2.以下代码为最新代码。
在使用适配器为ListView填充数据时,数据类型往往不是单一的,单一的数据显示太单调,对数据格式要求也比较高,我们在项目中往往使用网络请求获取json数据然后将其显示在Item中,此时获取的数据类型可能会有两到三种格式,此时就用到了分类适配,使用分类适配可以更加友好显示ListView
既然需要分类适配,我们就必须拿到数据的类型,你的数据也就必须直接或者间接的实现获取类型的方法,其实ListView中已经包含了这个获取类型的方法,当然你也可以使用自己的获取类型的方法
@Override
public int getItemViewType(int position) {
int type = Integer.parseInt(newsEntities.get(position).getType());
return type;
}
@Override
public int getViewTypeCount() {
return count;
}
进行分类适配
public View getView(int position, View convertView, ViewGroup parent) {
if (getItemViewType(position) == 1) {
ViewHolderVertical holder = null;
if (convertView == null) {
convertView = layoutInflater.inflate(
R.layout.item_firstpagelist_vertical, parent, false);
holder = new ViewHolderVertical();
holder.iv = (ImageView) convertView
.findViewById(R.id.item_firstpagelist_vertical_iv);
convertView.setTag(holder);
} else {
holder = (ViewHolderVertical) convertView.getTag();
}
NewsEntity entity = newsEntities.get(position);
} else {
ViewHolder holder = null;
if (convertView == null) {
convertView = layoutInflater.inflate(
R.layout.item_firstpagelist_horizontal, parent, false);
holder = new ViewHolder();
holder.iv = (ImageView) convertView
.findViewById(R.id.item_firstpagelist_iv);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
NewsEntity entity = newsEntities.get(position);
}
return convertView;
}
(下面这一段是没有更新之前,我使用key存放tag的方法,了解了listview内部有缓冲区上之后就放弃使用这种方法了,可以不看,但是我做了保留,算是了解一下这个方法吧。)在getView()中适配数据时,需要按照类型适配,假定有两种数据类型,我们就要有两个不一样的ViewHolder,传统实现代码如下
public View getView(int position, View convertView, ViewGroup parent) {
if (getItemViewType(position) == 1) {
ViewHolderVertical holder = null;
if (convertView == null) {
convertView = layoutInflater.inflate(
R.layout.item_firstpagelist_vertical, parent, false);
holder = new ViewHolderVertical();
holder.iv = (ImageView) convertView
.findViewById(R.id.item_firstpagelist_vertical_iv);
convertView.setTag(holder);
} else {
holder = (ViewHolderVertical) convertView.getTag();
}
NewsEntity entity = newsEntities.get(position);
} else {
ViewHolder holder = null;
if (convertView == null || convertView.getTag(R.string.k1) == null) {
convertView = layoutInflater.inflate(
R.layout.item_firstpagelist_horizontal, parent, false);
holder = new ViewHolder();
holder.iv = (ImageView) convertView
.findViewById(R.id.item_firstpagelist_iv);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
NewsEntity entity = newsEntities.get(position);
}
return convertView;
}
private class ViewHolder {
ImageView iv;
TextView tv_summary;
TextView tv_comment;
TextView tv_title;
}
private class ViewHolderVertical {
ImageView iv;
TextView tv_comment;
TextView tv_title;
}
代码可能稍微繁琐,大致思路就是根据type不同装载 不同的布局,设置不同的数据,这里我习惯性的使用了复用,当然也可以使用我上一篇文章写的抽象适配器,应该会简单一些。详情这里
但是这样会出现一个问题,就是在复用问题上,了解过ListView就会了解ListView内部维护了一组Item,当有Item滚出屏幕时就会被回收,新进入的Item就可以复用这些回收的Item,这样不会创建大量的UI,造成内存的浪费,因为滑出屏幕的Item是完全没有用的,那我们可以设想一下他的复用机制,当滑动屏幕时,新进入了一个type == 1的数据对象有待显示,但是此时复用的确实一个原本用来显示type == 2 的Item,自然就会NullPointError,因为Id已经查找不到了,所以解决复用的问题,本质就是解决如何根据type不同获取到不同类型的ViewHolder,Android已经考虑到了这一点,在convertView.setTag()不知道大家是否注意过有两个重载的方法
convertView.setTag(tag)
convertView.setTag(key, tag)
此时问题的解决办法就很明了,那就是不同的类型的ViewHolder设置为convertView的tag标签时添加一个唯一的key,就可以获取到正确类型的Item了,改进代码
public View getView(int position, View convertView, ViewGroup parent) {
if (getItemViewType(position) == 1) {
ViewHolderVertical holder = null;
if (convertView == null || convertView.getTag(R.string.k2) == null) {
convertView.setTag(R.string.k2, holder);
} else {
holder = (ViewHolderVertical) convertView.getTag(R.string.k2);
}
} else {
ViewHolder holder = null;
if (convertView == null || convertView.getTag(R.string.k1) == null) {
convertView.setTag(R.string.k1, holder);
} else {
holder = (ViewHolder) convertView.getTag(R.string.k1);
}
}
return convertView;
}
注意:
1.if判断,不仅仅是convertView!=null,如果只是这样,如果你是type1的数据,当你拿到type2的Item时事实上convertView仍然不是空的,此时会直接进入gettag()代码段,那你用type1的key值取出的必然是空的,所以加一个判断如果convertView.getTag(key)为空,难么说明不是这个类型的需要重新获取新的ViewHolder而不是走复用的路。
2.key值,之前我自己试过,既然key值是int类型就随便写一个,或者public static fianl int.....
就可以了,事实上是不可行的,报一个错误就是必须使用系统id作为键值,这里推荐
<string name="k1">k1</string>
<string name="k2">k2</string>