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

来源:互联网 发布:mysql两表关联update 编辑:程序博客网 时间:2024/05/18 02:24

我在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 ?!千千万万只草泥马在我内心翱翔啊~~~~我开始怀疑是什么地方出了问题,于是我回归了代码。

@Overridepublic 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;    }}@Overridepublic 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 (别废话上代码(╰_╯)#)
@Overridepublic View getView(int position, View convertView, ViewGroup parent) {    ...    holder.btn1.setTag(position);    holder.btn2.setTag(position);    holder.btn3.setTag(position);    return view;}@Overridepublic 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设置进去
@Overridepublic 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;}@Overridepublic 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方法巴拉巴拉~具体看代码

@Overridepublic 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
原创粉丝点击