关于adapter去重复的问题其实是个很简单的问题,很多人没有理解到list,grid以及recyclerview重复利用item以及使用viewholder的原理,所以在去重的道路上走得很坎坷,在这里小羽带着大家去好好的学习和总结一下item的知识,然后使用十分简洁的方案去有效的解决重复使用item带来的问题。

1.认识item的重复使用和viewholder的出现

item的重复使用目的是为了解决大量的list数据消耗大量的视图空间,而viewholder的出现是系统在解决数据显示的时候做的一种方案。

而这种方案主要针对的是重复的item但是数据不同。通过tag去绑定在item上然后再取得使用。

保证了每个已经创建的item上一定有个viewholder,所以每次刷新item的时候都必须要把数据和各种状态绑定一遍,否则滑动的时候就会有重复显示的问题。

2.从系统原理上去去重复

上面我们讲了item通过viewholder去解决数据重复的方案,虽然有点繁琐,但是有效可行。
有人要问:“如果我想改变某个item的属性又不想重复使用导致其他item属性也改变,什么办法好用呢?”。
这个问题最近的项目里我也遇到了。而且是一个item里面有两个子item,这两个子item也要一摸一样,但是不能同时干扰。
需要做属性动画去改变样式!!(是不是很蛋疼?毕竟公司想要炫酷,那我们就按需设计呗!)。
既然item重复利用,那么item的子控件都会是同一个对象。
所以小羽滋生了一种想法,既然控件是一样的,那么我可以记录一个当前选中的item或者它的一个控件,如果是当前item并且对应的position也是一样的,那么肯定是当前的item可以做改变,当滑动到重复利用的item时,虽然也是当前的item但是position却不一样,所以这时候就做默认的设置。
当滑回来的时候满足前面的条件所以又会继续改变。为什么可以这么自信的使用这种方案?原因很简单。
系统在重复利用item的时候是做过处理的,重复利用的这个item不可能和上个item同时出现在屏幕上。
所以我们不需要像viewholder一样把每种状态都做改变,因为即使此刻的上一个item的属性会随着当前item属性改变而改变,放心你是看不见的,所以我们不必担心这种方案的不可行!

3.源码分析

//recyclerview的adapter开始BindViewHolder
    @Override
    public void onBindViewHolder(RecViewHolder holder, final int position) {
        if(!Utils.listIsEmpty(mTopPaymentTypes) && mTopPaymentTypes.size() > position){
            PaymentType topPaymentType = mTopPaymentTypes.get(position);
            initPayBtnResource(holder.topPayViewItem, position, topPaymentType);
        }

        if(!Utils.listIsEmpty(mBottomPaymentTypes) && mBottomPaymentTypes.size() > position){
            PaymentType bottomPaymentType = mBottomPaymentTypes.get(position);
            initPayBtnResource(holder.bottomPayViewItem, position,bottomPaymentType);
        }
    }

    //设置item数据
    private void initPayBtnResource(View itemView, int position, PaymentType paymentType) {
        TextView payTypeName = (TextView) itemView.findViewById(R.id.payview_item_name);
        ImageView payTypeImage = (ImageView) itemView.findViewById(R.id.payview_item_image);
        View payTypeLight = itemView.findViewById(R.id.payview_item_light);
        PayTypeSource paySource = mPaySources.get(paymentType);
        if (paySource != null) {
            payTypeName.setText(paySource.getPayTypeName());
            //viewholder绑定item数据
            bindItemData(View itemView, int position, PaymentType paymentType);

            //下面这段语句就是解决item重复使用修改属性导致其他item出现问题的方案。
            if (mCheckedPayType == paymentType) {
                startLightAnimator();
                mAnimPayLight = payTypeLight;
            } else {
                if (mAnimPayLight == payTypeLight) {
                    endLightAnimator();
                }
            }
        }

        if (isSinglePay) {
            itemView.setOnClickListener(null);
            itemView.setBackgroundResource(R.drawable.pay_item_uncheck);
        } else {
            itemView.setOnClickListener(mClick);
            itemView.setTag(paymentType);
            itemView.setBackgroundResource(R.drawable.pay_item_can_change);
        }
    }

4.总结该方案!

这个方案只在单个item重复使用的时候才会被调用做改变,不需要每个item都去改变属性来保持平衡,非常简单直观的解决的重复利用的问题,从代码的简洁和系统执行的效率上说,都比较优,缺点就是多占了一个引用的内存,性价比上来说非常的靠谱。
有人肯定要问后面的endLightAnimator();只结束了动画但是属性还是变了。
这里小羽不得不吐槽一句了:“每个人的项目需求不一样,我这里是浮光效果,不选中的时候我可以直接把浮光隐藏掉就行了,至于这个属性在那个位置都不重要了”。
那么如果是一定要显示的去改变属性呢?这个小羽在3里面就说了,默认属性,就是比如你贴了一个机器人,要把他变成瘦机器人,那么这里end的时候直接赋值一个原来的机器人.方案是对的,问题是解决问题的需求不一样大家要按照自己的需求去实现。
原谅小羽不能贴出所有代码(虽然代码是自己写的,但是作为公司商业化产品,部分保密还是需要的)。