Android适配器进阶之二(分类适配器)

Android分类适配

我的CSDN博客

我的GitHub

我的GitHub博客


适配器的总结和使用

最新源代码下载

访问密码 9b16

更新:

1.放弃使用键值来判断tag的方式,使用listview本身提供的方式。

2.以下代码为最新代码。

在使用适配器为ListView填充数据时,数据类型往往不是单一的,单一的数据显示太单调,对数据格式要求也比较高,我们在项目中往往使用网络请求获取json数据然后将其显示在Item中,此时获取的数据类型可能会有两到三种格式,此时就用到了分类适配,使用分类适配可以更加友好显示ListView

既然需要分类适配,我们就必须拿到数据的类型,你的数据也就必须直接或者间接的实现获取类型的方法,其实ListView中已经包含了这个获取类型的方法,当然你也可以使用自己的获取类型的方法
//重写以下两个方法,listview在内部会准备getViewTypeCount()个缓冲区,用来复用同种类型的View,不同类型的View不会出现复用错误。
@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作为键值,这里推荐
//使用R.string.k1作为键值
<string name="k1">k1</string>
<string name="k2">k2</string>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值