我在Adapter中使用holder时踩到的坑

我在Adapter中使用holder时踩到的坑

说到这个坑,一切都源于万恶的用户需求,下面且听我娓娓道来。

最开始我们界面大概是这个样子滴~(以下图乃本人简画所得,真实设计比这个好很多滴)

简化版界面

要完成这个界面是不是so easy! 一个ListView,set一个Adapter,Adapter里对应绑定一个layout,完成啦~然后我就可以高高兴兴领盒饭啦~

BUT!

用户说,我们要求复制text的文字,我们要求在text旁边加一个按钮!

SO…我们的界面变成下面这个样子

这里写图片描述

哎呀,这也简单嘛,无非就是在layout里面多加个button嘛对不对~所以我就愉快的在layout里加上了这个胖胖的button,然后如往常一样,给button绑定一个onClickListener处理复制事件,收工!

然后我信心满满的点了一下Text 1旁边的copy按钮,随便打开一个可以粘贴的地方,粘贴!然后神奇的事情发生了…

妈蛋粘到这里的不是Text 1而是Text 7 !!!!然而我并不相信!于是我又复制了Text 2,粘贴,我擦为什么是Text 8?!我又继续回去实验,复制Text 4的内容,粘贴,怎么又是Text 7 ?!千千万万只草泥马在我内心翱翔啊~~~~我开始怀疑是什么地方出了问题,于是我回归了代码。

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View view = convertView;
    this.position = position;
    if (view == null) {
        view = LayoutInflater.from(getBaseContext()).inflate(R.layout.item_layout, parent, false);
        holder = new Holder();
        holder.t1 = (TextView) view.findViewById(R.id.t1);
        holder.t2 = (TextView) view.findViewById(R.id.t2);
        holder.t3 = (TextView) view.findViewById(R.id.t3);
        holder.btn1 = (Button) view.findViewById(R.id.btn1);
        holder.btn2 = (Button) view.findViewById(R.id.btn2);
        holder.btn3 = (Button) view.findViewById(R.id.btn3);
        view.setTag(holder);
    } else {
        holder = (Holder) view.getTag();
    }
    holder.btn1.setOnClickListener(this);
    holder.btn2.setOnClickListener(this);
    holder.btn3.setOnClickListener(this);
    holder.t1.setText(copies.get(position).str1);
    holder.t2.setText(copies.get(position).str2);
    holder.t3.setText(copies.get(position).str3);
    return view;
    }
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.btn1:
            copy(copies.get(position).str1);
            break;
        case R.id.btn2:
            copy(copies.get(position).str2);
            break;
        case R.id.btn3:
            copy(copies.get(position).str3);
            break;
    }
}

看起来似乎没啥问题对不对… 等等,是不是复用视图搞出的鬼?于是上网查了相关资料,发现了原来问题果然出在这里:

ListView只会缓存第一屏里面的List Item的视图布局,之后滚动ListView后面的Item的布局就都是用前面所缓存的视图布局(也就是convertView不为null)。

当超出第一屏的item被滑出来则会重新更新视图,所以此时的position会被赋为未滑动前被隐藏的item的position,进而取出缓存的视图进行更新。

因此只要保证position正确我们就成功了~
所以我总结了三种方法可以进行修改:

  • 方法1 用setTag方法记录position (别废话上代码(╰_╯)#)
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ...
    holder.btn1.setTag(position);
    holder.btn2.setTag(position);
    holder.btn3.setTag(position);
    return view;
}
@Override
public void onClick(View v) {
    //这里要强转为Integer哦
    int position = (Integer) v.getTag();
    switch (v.getId()) {
        case R.id.btn1:
            copy(copies.get(position).str1);
            break;
        case R.id.btn2:
            copy(copies.get(position).str2);
            break;
        case R.id.btn3:
            copy(copies.get(position).str3);
            break;
    }
}

好,下面介绍第二种方法,这个方法简单粗暴~

  • 方法2 用setTag方法将对应的String设置进去
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ...
    holder.btn1.setTag(copies.get(position).str1);
    holder.btn2.setTag(copies.get(position).str2);
    holder.btn3.setTag(copies.get(position).str3);
    return view;
}
@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.btn1:
        case R.id.btn2:
        case R.id.btn3:
        copy((String) v.getTag());
        break;
    }
}

完成啦~是不是炒鸡简单~

  • 方法3 略微麻烦

下面是最后一种方法啦~当当当,那就是自定义一个类实现OnClickListener接口,重写onClick方法,并且类里增加一个setPosition方法巴拉巴拉~具体看代码

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View view = convertView;
    this.position = position;
    OnCopyClickListener onCopyClickListener;
    if (view == null) {
        ...
    onCopyClickListener = new OnCopyClickListener();
    holder.btn1.setOnClickListener(onCopyClickListener);
    view.setTag(holder.btn1.getId(), onCopyClickListener);
    ...
    } else {
        holder = (Holder) view.getTag();
        onCopyClickListener = (OnCopyClickListener) view.getTag(holder.btn1.getId());
    }
    ...
    onCopyClickListener.setPosition(position);
    return view;
}
class OnCopyClickListener implements View.OnClickListener {
    int position;
    public void setPosition(int position) {
        this.position = position;
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn1:
                copy(copies.get(position).str1);
                break;
                ...
        }
    }
}

这是网友给出的方法,略复杂,但当时楼主居然用这么复杂的方法实现了,也是脑子瓦塔啦,大家也就看看就可以啦~~

细心的朋友会说了:你这不是都用的setTag实现的吗!有什么区别啊!你在逗我们啊!

哈哈哈确实,虽然楼主提供了三种方法,其实核心实现都是靠setTag方法,但是setTag的确是复用机制的好伴侣啊哈哈哈~~~

好啦,本篇博客就到这里啦~ 概括来说这篇主要是讲楼主在项目中踩到的holder的坑,为避免大家再次踩坑所以写了这篇文章,不足之处还请大家多多指教啦~~~
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值