AbsListView$RecycleBin简析

RecycleBin可以说是AbsListView视图复用的核心工具类了。
其中最核心的成员变量应该就是mActivityViews和mScrapViews了。本文主要对RecycleBin中一些方法的功能做了简要的概述。有几句代码的功能其实我也还不太清楚,不过也不太影响我们对RecycleBin功能的理解了。

/**
 * The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of
 * storage: ActiveViews and ScrapViews. ActiveViews are those views which were onscreen at the
 * start of a layout. By construction, they are displaying current information. At the end of
 * layout, all views in ActiveViews are demoted to ScrapViews. ScrapViews are old views that
 * could potentially be used by the adapter to avoid allocating views unnecessarily.
 *
 * @see android.widget.AbsListView#setRecyclerListener(android.widget.AbsListView.RecyclerListener)
 * @see android.widget.AbsListView.RecyclerListener
 */
class RecycleBin {
    // 当view被移动到scrap堆时的回调
    private RecyclerListener mRecyclerListener;
    // 存储在mActrivityViews中的第一个View(mActivityViews[0])在AbsListView中的position
    private int mFirstActivePosition;
    // ArrayList数组,缓存各种ViewType的视图,Adapter.getView方法参数中的convertView就是从这里来的
    private View[] mActiveViews = new View[0];
    // ArrayList数组,缓存各种ViewType的视图,Adapter.getView方法参数中的convertView就是从这里来的
    private ArrayList<View>[] mScrapViews;
    // 对应Adapter.getViewTypeCOunt()
    private int mViewTypeCount;

    private ArrayList<View> mCurrentScrap;

    private ArrayList<View> mSkippedScrap;

    private SparseArray<View> mTransientStateViews;
    private LongSparseArray<View> mTransientStateViewsById;
    // 初始化mViewTypeCount、mScrapViews,并设置mCurrentScrap为mScrapViews[0]
    public void setViewTypeCount(int viewTypeCount) {
        if (viewTypeCount < 1) {
            throw new IllegalArgumentException("Can't have a viewTypeCount < 1");
        }
        //noinspection unchecked
        ArrayList<View>[] scrapViews = new ArrayList[viewTypeCount];
        for (int i = 0; i < viewTypeCount; i++) {
            scrapViews[i] = new ArrayList<View>();
        }
        mViewTypeCount = viewTypeCount;
        mCurrentScrap = scrapViews[0];
        mScrapViews = scrapViews;
    }
    // 调用保存在mScrapViews、mTransientStateViews、mTransientStateViewsById中view的forceLayout方法
    public void markChildrenDirty() {
        if (mViewTypeCount == 1) {
            final ArrayList<View> scrap = mCurrentScrap;
            final int scrapCount = scrap.size();
            for (int i = 0; i < scrapCount; i++) {
                scrap.get(i).forceLayout();
            }
        } else {
            final int typeCount = mViewTypeCount;
            for (int i = 0; i < typeCount; i++) {
                final ArrayList<View> scrap = mScrapViews[i];
                final int scrapCount = scrap.size();
                for (int j = 0; j < scrapCount; j++) {
                    scrap.get(j).forceLayout();
                }
            }
        }
        if (mTransientStateViews != null) {
            final int count = mTransientStateViews.size();
            for (int i = 0; i < count; i++) {
                mTransientStateViews.valueAt(i).forceLayout();
            }
        }
        if (mTransientStateViewsById != null) {
            final int count = mTransientStateViewsById.size();
            for (int i = 0; i < count; i++) {
                mTransientStateViewsById.valueAt(i).forceLayout();
            }
        }
    }

    public boolean shouldRecycleViewType(int viewType) {
        return viewType >= 0;
    }

    // 清空mScrapViews、mTransientStateViews、mTransientStateViewsById从的视图,并调用ViewGroup.removeDetachedView移除
    void clear() {
        if (mViewTypeCount == 1) {
            final ArrayList<View> scrap = mCurrentScrap;
            clearScrap(scrap);
        } else {
            final int typeCount = mViewTypeCount;
            for (int i = 0; i < typeCount; i++) {
                final ArrayList<View> scrap = mScrapViews[i];
                clearScrap(scrap);
            }
        }

        clearTransientStateViews();
    }

    // 填充mActivityViews,视图要求:LayoutParams不得为null,不得为header或者footer
    void fillActiveViews(int childCount, int firstActivePosition) {
        if (mActiveViews.length < childCount) {
            mActiveViews = new View[childCount];
        }
        mFirstActivePosition = firstActivePosition;

        //noinspection MismatchedReadAndWriteOfArray
        final View[] activeViews = mActiveViews;
        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);
            AbsListView.LayoutParams lp = (AbsListView.LayoutParams) child.getLayoutParams();
            // 不为header或footer,并且LayoutParams不为null才会填充
            if (lp != null && lp.viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
                activeViews[i] = child;
            }
        }
    }
    // 从mActiveViews获取指定position的View,并从mActiveViews中移除该View
    View getActiveView(int position) {
        int index = position - mFirstActivePosition;
        final View[] activeViews = mActiveViews;
        if (index >=0 && index < activeViews.length) {
            final View match = activeViews[index];
            activeViews[index] = null;
            return match;
        }
        return null;
    }

    View getTransientStateView(int position) {
        // mAdapterHasStableIds的值为mAdapter.hasStableIds(),在setAdapter时会被设置
        if (mAdapter != null && mAdapterHasStableIds && mTransientStateViewsById != null) {
            // 从mTransientStateViewsById中获取
            long id = mAdapter.getItemId(position);
            View result = mTransientStateViewsById.get(id);
            mTransientStateViewsById.remove(id);
            return result;
        }
        if (mTransientStateViews != null) {
            // 从mTransientStateViews中获取
            final int index = mTransientStateViews.indexOfKey(position);
            if (index >= 0) {
                View result = mTransientStateViews.valueAt(index);
                mTransientStateViews.removeAt(index);
                return result;
            }
        }
        return null;
    }

    /**
     * 清空mTransientStateViews和mTransientStateViewsById
     */
    void clearTransientStateViews() {
        final SparseArray<View> viewsByPos = mTransientStateViews;
        if (viewsByPos != null) {
            final int N = viewsByPos.size();
            for (int i = 0; i < N; i++) {
                removeDetachedView(viewsByPos.valueAt(i), false);
            }
            viewsByPos.clear();
        }

        final LongSparseArray<View> viewsById = mTransientStateViewsById;
        if (viewsById != null) {
            final int N = viewsById.size();
            for (int i = 0; i < N; i++) {
                removeDetachedView(viewsById.valueAt(i), false);
            }
            viewsById.clear();
        }
    }

    /**
     * 从缓存中获取一个备用视图
     */
    View getScrapView(int position) {
        if (mViewTypeCount == 1) {
            // viewtype为1,那么直接从mCurrentScrap中获取
            return retrieveFromScrap(mCurrentScrap, position);
        } else {
            // viewtype不为1,获取position对应的type,然后以此为下标,从mScrapViews中获取
            final int whichScrap = mAdapter.getItemViewType(position);
            if (whichScrap >= 0 && whichScrap < mScrapViews.length) {
                return retrieveFromScrap(mScrapViews[whichScrap], position);
            }
        }
        return null;
    }

    /**
     * Puts a view into the list of scrap views.
     * 向缓存中放入一个视图
     * @param scrap The view to add
     * @param position The view's position within its parent
     *     该视图在其父布局中的position
     */
    void addScrapView(View scrap, int position) {
        final AbsListView.LayoutParams lp = (AbsListView.LayoutParams) scrap.getLayoutParams();
        // 不添加LayoutParams为null的视图
        if (lp == null) {
            return;
        }
        // 记录位置
        lp.scrappedFromPosition = position;

        // header或footer的viewType为-2
        final int viewType = lp.viewType;
        if (!shouldRecycleViewType(viewType)) {
            // 如果viewType小于0那么直接return,不进行回收
            return;
        }

        scrap.dispatchStartTemporaryDetach();

        // The the accessibility state of the view may change while temporary
        // detached and we do not allow detached views to fire accessibility
        // events. So we are announcing that the subtree changed giving a chance
        // to clients holding on to a view in this subtree to refresh it.
        notifyViewAccessibilityStateChangedIfNeeded(
                AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);

        // 如果有Transient State那么不放到mScrapViews中
        final boolean scrapHasTransientState = scrap.hasTransientState();
        if (scrapHasTransientState) {
            if (mAdapter != null && mAdapterHasStableIds) {
                // 放到mTransientStateViewsById中
                if (mTransientStateViewsById == null) {
                    mTransientStateViewsById = new LongSparseArray<View>();
                }
                mTransientStateViewsById.put(lp.itemId, scrap);
            } else if (!mDataChanged) {
                // 放到mTransientStateViews中
                if (mTransientStateViews == null) {
                    mTransientStateViews = new SparseArray<View>();
                }
                mTransientStateViews.put(position, scrap);
            } else {
                // 放到mSkippedScrap中
                if (mSkippedScrap == null) {
                    mSkippedScrap = new ArrayList<View>();
                }
                mSkippedScrap.add(scrap);
            }
        } else {
            // 放到mScrapViews中
            if (mViewTypeCount == 1) {
                mCurrentScrap.add(scrap);
            } else {
                mScrapViews[viewType].add(scrap);
            }
            // 回调 
            if (mRecyclerListener != null) {
                mRecyclerListener.onMovedToScrapHeap(scrap);
            }
        }
    }

    /**
     * 清空mSkippedScrap
     */
    void removeSkippedScrap() {
        if (mSkippedScrap == null) {
            return;
        }
        final int count = mSkippedScrap.size();
        for (int i = 0; i < count; i++) {
            removeDetachedView(mSkippedScrap.get(i), false);
        }
        mSkippedScrap.clear();
    }

    /**
     * 转移mActiveViews中的view到mScrapViews中去,一般是在layout尾声的时候被调用
     */
    void scrapActiveViews() {
        final View[] activeViews = mActiveViews;
        final boolean hasListener = mRecyclerListener != null;
        final boolean multipleScraps = mViewTypeCount > 1;

        ArrayList<View> scrapViews = mCurrentScrap;
        final int count = activeViews.length;
        for (int i = count - 1; i >= 0; i--) {
            final View victim = activeViews[i];
            if (victim != null) {
                final AbsListView.LayoutParams lp
                        = (AbsListView.LayoutParams) victim.getLayoutParams();
                final int whichScrap = lp.viewType;
                // 从mActiveViews中移除
                activeViews[i] = null;

                if (victim.hasTransientState()) {
                    // 视图拥有Transient State

                    // Store views with transient state for later use.
                    victim.dispatchStartTemporaryDetach();

                    if (mAdapter != null && mAdapterHasStableIds) {
                        // 放到mTransientStateViewsById中
                        if (mTransientStateViewsById == null) {
                            mTransientStateViewsById = new LongSparseArray<View>();
                        }
                        long id = mAdapter.getItemId(mFirstActivePosition + i);
                        mTransientStateViewsById.put(id, victim);
                    } else if (!mDataChanged) {
                        // 放到mTransientStateViews中
                        if (mTransientStateViews == null) {
                            mTransientStateViews = new SparseArray<View>();
                        }
                        mTransientStateViews.put(mFirstActivePosition + i, victim);
                    } else if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
                        // 数据源都改变了,留它无用。。
                        removeDetachedView(victim, false);
                    }
                } else if (!shouldRecycleViewType(whichScrap)) {
                    // 不允许回收
                    // 移除所有非header、footer的视图
                    if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
                        removeDetachedView(victim, false);
                    }
                } else {
                    // 转移到mScrapViews中
                    if (multipleScraps) {
                        scrapViews = mScrapViews[whichScrap];
                    }

                    victim.dispatchStartTemporaryDetach();
                    lp.scrappedFromPosition = mFirstActivePosition + i;
                    scrapViews.add(victim);
                    // 回调
                    if (hasListener) {
                        mRecyclerListener.onMovedToScrapHeap(victim);
                    }
                }
            }
        }
        // 别急,马上就讲
        pruneScrapViews();
    }

    /**
     * Makes sure that the size of mScrapViews does not exceed the size of
     * mActiveViews, which can happen if an adapter does not recycle its
     * views. Removes cached transient state views that no longer have
     * transient state.
     * 确保mScrapViews的大小不会超过mActiveViews。这种情况有可能发生在adapter没有回收view
     * 删除不再有transient state的view
     */
    private void pruneScrapViews() {
        final int maxViews = mActiveViews.length;
        final int viewTypeCount = mViewTypeCount;
        final ArrayList<View>[] scrapViews = mScrapViews;
        for (int i = 0; i < viewTypeCount; ++i) {
            final ArrayList<View> scrapPile = scrapViews[i];
            int size = scrapPile.size();
            final int extras = size - maxViews;
            size--;
            for (int j = 0; j < extras; j++) {
                removeDetachedView(scrapPile.remove(size--), false);
            }
        }

        final SparseArray<View> transViewsByPos = mTransientStateViews;
        if (transViewsByPos != null) {
            for (int i = 0; i < transViewsByPos.size(); i++) {
                final View v = transViewsByPos.valueAt(i);
                if (!v.hasTransientState()) {
                    removeDetachedView(v, false);
                    transViewsByPos.removeAt(i);
                    i--;
                }
            }
        }

        final LongSparseArray<View> transViewsById = mTransientStateViewsById;
        if (transViewsById != null) {
            for (int i = 0; i < transViewsById.size(); i++) {
                final View v = transViewsById.valueAt(i);
                if (!v.hasTransientState()) {
                    removeDetachedView(v, false);
                    transViewsById.removeAt(i);
                    i--;
                }
            }
        }
    }

    /**
     * 将mScrapViews中所有的视图放到所提供的List中
     */
    void reclaimScrapViews(List<View> views) {
        if (mViewTypeCount == 1) {
            views.addAll(mCurrentScrap);
        } else {
            final int viewTypeCount = mViewTypeCount;
            final ArrayList<View>[] scrapViews = mScrapViews;
            for (int i = 0; i < viewTypeCount; ++i) {
                final ArrayList<View> scrapPile = scrapViews[i];
                views.addAll(scrapPile);
            }
        }
    }

    /**
     * Updates the cache color hint of all known views.
     * 更新mScrapViews、mActiveViews中所有视图的DrawingCache
     */
    void setCacheColorHint(int color) {
        if (mViewTypeCount == 1) {
            final ArrayList<View> scrap = mCurrentScrap;
            final int scrapCount = scrap.size();
            for (int i = 0; i < scrapCount; i++) {
                scrap.get(i).setDrawingCacheBackgroundColor(color);
            }
        } else {
            final int typeCount = mViewTypeCount;
            for (int i = 0; i < typeCount; i++) {
                final ArrayList<View> scrap = mScrapViews[i];
                final int scrapCount = scrap.size();
                for (int j = 0; j < scrapCount; j++) {
                    scrap.get(j).setDrawingCacheBackgroundColor(color);
                }
            }
        }
        // Just in case this is called during a layout pass
        final View[] activeViews = mActiveViews;
        final int count = activeViews.length;
        for (int i = 0; i < count; ++i) {
            final View victim = activeViews[i];
            if (victim != null) {
                victim.setDrawingCacheBackgroundColor(color);
            }
        }
    }
    // 从指定的scrapViews中获取指定position的视图
    private View retrieveFromScrap(ArrayList<View> scrapViews, int position) {
        final int size = scrapViews.size();
        if (size > 0) {
            // See if we still have a view for this position or ID.
            for (int i = 0; i < size; i++) {
                final View view = scrapViews.get(i);
                final AbsListView.LayoutParams params =
                        (AbsListView.LayoutParams) view.getLayoutParams();

                if (mAdapterHasStableIds) {
                    final long id = mAdapter.getItemId(position);
                    if (id == params.itemId) {
                        return scrapViews.remove(i);
                    }
                } else if (params.scrappedFromPosition == position) {
                    final View scrap = scrapViews.remove(i);
                    clearAccessibilityFromScrap(scrap);
                    return scrap;
                }
            }
            final View scrap = scrapViews.remove(size - 1);
            clearAccessibilityFromScrap(scrap);
            return scrap;
        } else {
            return null;
        }
    }

    private void clearScrap(final ArrayList<View> scrap) {
        final int scrapCount = scrap.size();
        for (int j = 0; j < scrapCount; j++) {
            removeDetachedView(scrap.remove(scrapCount - 1 - j), false);
        }
    }

    private void clearAccessibilityFromScrap(View view) {
        if (view.isAccessibilityFocused()) {
            view.clearAccessibilityFocus();
        }
        view.setAccessibilityDelegate(null);
    }

    private void removeDetachedView(View child, boolean animate) {
        child.setAccessibilityDelegate(null);
        AbsListView.this.removeDetachedView(child, animate);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值