RecyclerView网络图像刷新会闪烁

转载:https://blog.csdn.net/qq_36523667/article/details/78736015

先看一下哪里来的stableId


stableId是Adapter中的一个成员变量,默认是false

public static abstract class Adapter<VH extends ViewHolder> {
    private final AdapterDataObservable mObservable = new AdapterDataObservable();
    private boolean mHasStableIds = false;

针对这个变量,Adapter类中有两个方法


其一,hasStableIds()、

public final boolean hasStableIds() {
    return mHasStableIds;
}

其二,setHasStableIds(boolean hasStableIds)

public void setHasStableIds(boolean hasStableIds) {
    if (hasObservers()) {
        throw new IllegalStateException("Cannot change whether this adapter has " +
                "stable IDs while the adapter has registered observers.");
    }
    mHasStableIds = hasStableIds;
}

但是我们很惊讶的发现,RecyclerView中根本就没有任何一处调用了setHasStableIds(boolean hasStableIds)方法把这个成员变量设为true,所以这很需要我们值得深思了。

所以我们只能根据hasStableIds()方法来弄明白这个mHasStableIds变量的意义。


第一处:hasStableIds()为false,判断条件为||,不影响结果

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

第二处:hasStableIds()为false,mState.mFocusedItemId被初始化为NO_ID。

mState.mFocusedItemId = mAdapter.hasStableIds() ? focusedVh.getItemId() : NO_ID;
追溯mState.mFocusedItemId,只有一处,此处因为NO_ID,无法进入if。追溯结束。

if (mState.mFocusedItemId != NO_ID && mAdapter.hasStableIds()) {
    focusTarget = findViewHolderForItemId(mState.mFocusedItemId);
}

第三处:由注释可知,这个方法返回一个独一无二的key,用于处理改变动画。可以说实在的,有没有stableId都一样

/**
 * Returns a unique key to be used while handling change animations.
 * It might be child's position or stable id depending on the adapter type.
 */
long getChangedHolderKey(ViewHolder holder) {
    return mAdapter.hasStableIds() ? holder.getItemId() : holder.mPosition;
}

对比这3处第二处是最有嫌疑的,只有当mState.mFocusedItemId 不被赋值为NO_ID且mAdapter.hasStableIds()是true,才进入这个if,非常符合我们想要追寻的结果。


找到使用这个方法的地方。

if (mState.mFocusedItemId != NO_ID && mAdapter.hasStableIds()) {
    focusTarget = findViewHolderForItemId(mState.mFocusedItemId);
}
View viewToFocus = null;
if (focusTarget == null || mChildHelper.isHidden(focusTarget.itemView)
        || !focusTarget.itemView.hasFocusable()) {
    if (mChildHelper.getChildCount() > 0) {
        // At this point, RV has focus and either of these conditions are true:
        // 1. There's no previously focused item either because RV received focused before
        // layout, or the previously focused item was removed, or RV doesn't have stable IDs
        // 2. Previous focus child is hidden, or 3. Previous focused child is no longer
        // focusable. In either of these cases, we make sure that RV still passes down the
        // focus to one of its focusable children using a best-effort algorithm.
        viewToFocus = findNextViewToFocus();
    }
} else {
    // looks like the focused item has been replaced with another view that represents the
    // same item in the adapter. Request focus on that.
    viewToFocus = focusTarget.itemView;
}

if (viewToFocus != null) {
    if (mState.mFocusedSubChildId != NO_ID) {
        View child = viewToFocus.findViewById(mState.mFocusedSubChildId);
        if (child != null && child.isFocusable()) {
            viewToFocus = child;
        }
    }
    viewToFocus.requestFocus();
}
直接定位到最后一行。

public final boolean requestFocus() {
    return requestFocus(View.FOCUS_DOWN);
}


由此我们得出结论,当你stableId设置为true的时候,等同于调用了viewholder中的view的requestFocus()方法。这个方法的作用是给这个请求requestFocus()的方法的view的下面的那个view焦点。

结合这篇文章,可以顺利使用stableId解决RecyclerView的notify方法使得图片加载时不闪烁。

猜你喜欢

转载自blog.csdn.net/qq_33330887/article/details/80168111