RecyclerView中及时创建和及时绑定的机制,保证稳定性的手段之一

在看RecyclerViewPool源码的时候,遇到了一个很有意思的方法。

void factorInCreateTime(int viewType, long createTimeNs) {
    ScrapData scrapData = getScrapDataForType(viewType);
    scrapData.mCreateRunningAverageNs = runningAverage(
            scrapData.mCreateRunningAverageNs, createTimeNs);
}
这个方法的作用是传入这一次创建view的创建时间,并且和以前创建的平均时间,经过算法,得出最新的创建这个view的平均时间。有人可能会很诧异,为什么要这样做?


那就要看看这个平均时间scrapData.mCreateRunningAverageNs是谁在调用了。我们发现了调用者

boolean willCreateInTime(int viewType, long approxCurrentNs, long deadlineNs) {
    long expectedDurationNs = getScrapDataForType(viewType).mCreateRunningAverageNs;
    return expectedDurationNs == 0 || (approxCurrentNs + expectedDurationNs < deadlineNs);
}
看名字就知道,这是对view能否及时创建进行的一个判断。而判断的依据就是这个平均时间。


能否及时创建会影响什么吗?我们继续追溯。

if (holder == null) {
    long start = getNanoTime();
    if (deadlineNs != FOREVER_NS
            && !mRecyclerPool.willCreateInTime(type, start, deadlineNs)) {
        // abort - we have a deadline we can't meet
        return null;
    }
Recycler在发现没有这种viewHolder的时候,他自然就不能从他的废品里拿出来去重用,所以我们只能创建。但是我们不能及时创建的时候,他会果断返回null,对于ViewHolder tryGetViewHolderForPositionByDeadline()方法。


根据这个方法的名字,我们知道了这个方法是用来取得viewholder的位置的。那返回了null后会有什么连锁反应呢?继续追溯。

public View getViewForPosition(int position) {
    return getViewForPosition(position, false);
}

View getViewForPosition(int position, boolean dryRun) {
    return tryGetViewHolderForPositionByDeadline(position, dryRun, FOREVER_NS).itemView;
}
相对应的,这个方法返回的也是空。


这个方法是抽象类LayoutManager的实现类会被使用的方法,我们需要在LinearLayoutManager中定位它。

View next(RecyclerView.Recycler recycler) {
    if (mScrapList != null) {
        return nextViewFromScrapList();
    }
    final View view = recycler.getViewForPosition(mCurrentPosition);
    mCurrentPosition += mItemDirection;
    return view;
}
我们可以得知,这是在视图绘制中layout方法中会调用的方法,目的就是取得下一个将要被layout的item。


正常情况下getViewForPosition()都不会返回空值,那为什么要叽叽歪歪这么一串东西呢?我们需要深究一下那个能否及时创建的方法。

boolean willCreateInTime(int viewType, long approxCurrentNs, long deadlineNs) {
    long expectedDurationNs = getScrapDataForType(viewType).mCreateRunningAverageNs;
    return expectedDurationNs == 0 || (approxCurrentNs + expectedDurationNs < deadlineNs);
}
(approxCurrentNs + expectedDurationNs < deadlineNs)。意思就是我们必须在截止日期前创建完。我们定位了一下这个截止日期deadlineNs,惊讶地发现它等于Long.MAX_VALUE。那岂不是永远都返回的是true?其实不是的。当开发人员逻辑错误的时候,或者其他未知错误,比如死循环,RecyclerView可能会通过他其他的措施给你救回来,但是你创建一个view平均的时间就会被增加到无穷大,那么当再次执行到这个错误的逻辑的时候,那么就会判断不通过,直接返回null,避免了第二次错误,或者更多次的错误导致整个程序的崩溃。所以这一点是他提升稳定性的手段,值得学习。


不过返回空还有另一种情况,可以追溯下next方法。

if (view == null) {
    if (DEBUG && layoutState.mScrapList == null) {
        throw new RuntimeException("received null view when unexpected");
    }
    // if we are laying out views in scrap, this may return null which means there is
    // no more items to layout.
    result.mFinished = true;
    return;
}
意思就是没有更多的items可以layout了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值