为什么选择放弃recyclerView

创建了2倍的viewHolder

假设只显示了n个item
1. 人们通常认为recyclerView最多只缓存n + 2个viewHolder,这是错误的,正确的答案是n * 2 + 2

解释,当item显示完全后,如果再次调用notifyItemChanged,那么会再次创建一个viewHolder,之后调用notifyItemChanged才不会调用createViewHolder, 关键是,这里notify之后调用的bindViewHolder是轮流使用这两个viewHolder(针对同一个item)
怎么做到只缓存n + 2个viewHolder,调用方法setItemAnimator(null), 动画的末尾会改变一个标志,这个标志,会影响mState.mRunPredictiveAnimations,这个如果为true,那么会多走一次mLayout.onLayoutChildren(mRecycler, mState); 如下代码



        mState.mRunSimpleAnimations = mState.mRunSimpleAnimations && mItemAnimator != null;

// anather method

        boolean animationTypeSupported = mItemsAddedOrRemoved || mItemsChanged;
        mState.mRunSimpleAnimations = mFirstLayoutComplete && mItemAnimator != null &&
            (mDataSetHasChangedAfterLayout || animationTypeSupported ||
                mLayout.mRequestedSimpleAnimations) &&
            (!mDataSetHasChangedAfterLayout || mAdapter.hasStableIds());
        mState.mRunPredictiveAnimations = mState.mRunSimpleAnimations &&
            animationTypeSupported && !mDataSetHasChangedAfterLayout &&
            predictiveItemAnimationsEnabled();

如果不用动画,那么和listView又有什么区别呢

scroll监听无效

滚动(scrollToPositionWithOffset), 当滚动到最后一页的时候,最上方显示了一个item的一半,假设显示的是6,5,4 和3的一半那么此时如果我要滚动到3,让3完全显示,6不完全显示,此时不会触发scroll监听,但是布局是有改变的,即以人的常识认为是有滑动的,详情如下代码

//dispatchLayout
        if (didChildRangeChange(mMinMaxLayoutPositions[0], mMinMaxLayoutPositions[1])) {
            dispatchOnScrolled(0, 0);
        }
    private boolean didChildRangeChange(int minPositionPreLayout, int maxPositionPreLayout) {
        int count = mChildHelper.getChildCount();
        if (count == 0) {
            return minPositionPreLayout != 0 || maxPositionPreLayout != 0;
        }
        // 判断当前布局的view的位置,是否和原来的不一样
        for (int i = 0; i < count; ++i) {
            final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
            if (holder.shouldIgnore()) {
                continue;
            }
            final int pos = holder.getLayoutPosition();
            if (pos < minPositionPreLayout || pos > maxPositionPreLayout) {
                return true;
            }
        }
        return false;
    }

scrollToPosition()问题

如果界面上显示了该位置的item,则界面不会滚动,改为调用scrollToPositionWithOffset方法

smoothScrollToPosition

同样存在上面的问题,分析了大半天源码,发现,这里可以这样修改自定义LinearSmoothScroller,重写如下方法,并且自定义LinearLayoutManager,重写smoothScrollToPosition方法,方法内使用的scroller替换成自定义的scroller
这里是从上往下布局,暂时没有发现改动造成的不适,可能从下往上布局会有影响,待验证;其余影响暂时只发现一点
当调用smothScroll的时候,不能notifyInset,会有无法插入的现象,即不会调用onbindViewHolder方法
具体可参考我的博文


    protected int getVerticalSnapPreference() {
//        return mTargetVector == null || mTargetVector.y == 0 ? SNAP_TO_ANY :
//               mTargetVector.y > 0 ? SNAP_TO_END : SNAP_TO_START;
        // //  TODO: 2017/2/28 这里修改是为了view已经在界面上存在的时候,也能够滚动
        return SNAP_TO_START;
    }

notifyItemChanged无效

有一个需求先把item展开出来,再显示具体的数据,从逻辑上来说,通用逻辑就是
expandItem->showData,也就是说我在presenter中调用了这两个方法,然后ui中每个方法都notifyItemChanged一次,最终只bindViewHolder了一次(第二次notify)

有人会说,你非要分两个方法那能怪谁,是的,不能怪谁,只是想逻辑上细分,也就是说所谓的单元化,或者说单一功能

两个position

viewHolder有连个getPosiiton的方法,一个是getAdapterPosition,一个是getLayoutPosition,到底该用哪个,我并不能分得清,在调试中,这两个值一直是相等的。

复用的处理比较复杂

当然了,并不是只有viewHolder有这种情况
考虑一下情景:
item0中有一个点赞按钮,假设访问服务用了30秒,
在第5秒的时候,我滚动了recyclerView,此时item0对应的viewHolder被复用,
第7秒我再滚动回来,此时item0对应的viewHolder不一定是原来的viewHolder,假设是viewHolder1。
假设网络超时,那么在访问结束的时候,我要重置item0的显示,也就是viewHolder1的显示,
也就是说,我操作了viewHolder0,服务返回的时候,要修改的是viewHolder1。
那么这个逻辑,如果要顺序处理,那么会比较复杂,特别是如果用了mvp,操作从v传到p,数据从p传到m,然后又要从m传会p,此时要处理的是哪一个视图,不管怎么,数据总是要来回传递的,至于视图….总之要考虑许多问题。
当然解决办法也有,神奇的eventBus(虽然不建议使用,但这里确实非常好用),
只需要服务返回之后发送一个event,然后界面接受到之后更新数据对应的item就行了。
不过有个问题,recyclerView更新item的动画会有一个闪一下的效果,非常不爽, 产品说必须去掉,我只更新这个操作的按钮不久行了?
然而,都没能获得viewHolder1的引用,如果更新这个按钮,所以得绕过去。修改更新item动画,简单,自定义动画,把default的复制过来,设置时间变短就行了。


最后欢迎关注我的微信公众号:云端看大地
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值