listview、gridview单项更新及滑动时数据错乱重复问题

来源:互联网 发布:淘宝搜索关键词排行榜 编辑:程序博客网 时间:2024/06/05 19:30

转载请注明出处:http://blog.csdn.net/ym4189/article/details/77503366

前言

listview和gridview原理是一样的,只是显示方式不一样。这里我就以gridview来说明
首先,为什么要单项更新?因为notifyDataSetChanged()方法是刷新整个数据,当我们的数据量很大时,原本只需要刷新一项,但是整个数据都刷新了,这会导致操作不流畅,因此单项刷新很有必要。

单项刷新

我这里的需求是监听gridview的点击事件,当点击某一项时把这一项标记为选择状态,再次点击时取消标记。这里使用List保存需要标记项的索引,当集合中包含当前项时,说明已经标记需要取消标记,反之标记当前项。

这里写图片描述

public List<String> mSelectedDelete = new LinkedList<String>();class OnGridItemClickClick implements OnItemClickListener {        @Override        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {                if (mSelectedDelete.contains(String.valueOf(position))) {                    mSelectedDelete.remove(String.valueOf(position));                    setItemStatus(position, false);                } else {                    mSelectedDelete.add(String.valueOf(position));                    setItemStatus(position, true);                }            }        }    }public void setItemStatus(int position, boolean b) {        View localView = getViewByPosition(position, gridView);        ImageView img = (ImageView) localView.findViewById(R.id.img_state);        if (b) {            img.setVisibility(View.VISIBLE);        } else {            img.setVisibility(View.GONE);        }    }//根据pos获得此项视图public View getViewByPosition(int pos, GridView gridView) {        int firstListItemPosition = gridView.getFirstVisiblePosition();        int lastListItemPosition = firstListItemPosition + gridView.getChildCount() - 1;        if (pos < firstListItemPosition || pos > lastListItemPosition) {            return gridView.getAdapter().getView(pos, null, gridView);        } else {            final int childIndex = pos - firstListItemPosition;            return gridView.getChildAt(childIndex);        }    }

数据错乱

这里写图片描述
可以看到,当我选中了第一个,但是在滑动过程中,没有被选中的项被标记为了选中状态,选中项数据错乱了。(根据情况的不同,数据可以是文本,checkbox的选中状态,图片,背景色,控件的显示状态等等…)

说道数据错乱,首先说一下listview、gridview的复用机制
这里写图片描述

上图可知listview的缓存优化机制,滚出屏幕的视图会被缓存下来并被复用。这种方法就出现了上述的问题,他会导致滑动时控件的数据错乱。解决也很简单,上面的mSelectedDelete 集合就派上用场了。
看代码:

public class GridViewAdapter extends BaseAdapter {        private Context mContext;        public GridViewAdapter(Context mContext) {            super();            this.mContext = mContext;        }        @Override        public int getCount() {            return imageInfoList.size();        }        @Override        public Object getItem(int position) {            return imageInfoList.get(position);        }        @Override        public long getItemId(int position) {            return position;        }        @Override        public View getView(final int position, View convertView, ViewGroup parent) {            ViewHolder holder = null;            if (convertView == null) {                holder = new ViewHolder();                convertView = LayoutInflater.from(this.mContext).inflate(R.layout.gridview_item_file, null, false);                holder.imgState = (ImageView) convertView.findViewById(R.id.img_state);                holder.imgFile = (ImageView) convertView.findViewById(R.id.img_file);                holder.relativeParent = (RelativeLayout) convertView.findViewById(R.id.relative_item);                convertView.setTag(holder);            } else {                holder = (ViewHolder) convertView.getTag();            }            if (imageInfoList != null) {                int width = gridView.getWidth() / 3;                int height = width;                RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(width, height);                holder.relativeParent.setLayoutParams(params);                String url = imageInfoList.get(position);                holder.imgFile.setVisibility(View.VISIBLE);                Glide.with(GridViewActivity.this).load(url).fitCenter().into(holder.imgFile);                //判断是否为标记项                if (mSelectedDelete.contains(String.valueOf(position)))                    // 显示                    holder.imgState.setVisibility(View.VISIBLE);                else                    // 隐藏                    holder.imgState.setVisibility(View.GONE);            }            return convertView;        }        private class ViewHolder {            RelativeLayout relativeParent;            ImageView imgState, imgFile;        }    }

在这里我的例子是view的显示状态,当然解决思路是一样的。代码中我用一个集合来保存需要标记的item的position值(这里不能直接保存int,要转成string,不然会格式混乱),在getView()中判断此项是否是被标记项来判断是否显示view。

这里写图片描述

ps:
最好的方式是建一个HashMap来保存两个数据,第一个就是item的position值,这个值表示的是item真正在listview的序号而不是页面上这个item所在的序号。第二个则是这个position的事件情况,可用false,true表示。 当更新数据时,同时更新HashMap里面对应项的状态,然后在getview中根据HashMap里面的对应状态去改变,这样数据事件就是根据HashMap中存入的数据来判断,而不是复用时的直接使用了。

阅读全文
0 0
原创粉丝点击