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方法使得圖片加載時不閃爍。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章