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