我在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的坑,为避免大家再次踩坑所以写了这篇文章,不足之处还请大家多多指教啦~~~
- 我在Adapter中使用holder时踩到的坑
- 在Adapter中使用Holder的那些坑
- 在Adapter中使用Holder的那些坑
- Android Adapter中使用Holder 需要注意的地方
- android 低耦合度的adapter与holder案例,使用butterknife
- Android中holder模式的使用
- Holder的使用
- holder.js的使用
- ndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter的解决方案
- Android RecyclerView Adapter及Holder的封装【原创】
- 关于Recycleview的Inconsistency detected. Invalid view holder adapter positionViewHolder
- 自定义listview holder 和adapter
- javax.xml.ws.Holder的使用方式
- 在ListFragment中使用base-adapter
- 在activity中使用adapter加载数据
- 在adapter 中进行数据的操作
- 在adapter中设置空白的
- listview的Adapter性能优化之viewholder终极用法,无需生成holder内部类类
- Range对象介绍
- android开发笔记之 AlarmManager(闹钟服务)
- Unity 官方案例 打砖块
- 关于python字符串的处理
- 数据结构之魔方程序
- 我在Adapter中使用holder时踩到的坑
- 乱码问题
- 手机服务 取得电池电量信息
- Android-Intent详解
- 【set】
- 关于找工作
- PHP的ffmpeg使用
- 2016"百度之星" - 资格赛(Astar Round1)Problem D(map+string)
- HTML-通过点击网页上的文字弹出QQ添加好友页面