Android Adapter机制 源码笔记(6): AbsListView(2)

  1. AbsListView中的回收器: RecycleBin: RecycleBin实现了在一次一次的layout的过程中对于View的回收重用机制, 有两层的的view storage: ActiveViews层和ScrapViews层. 其中,ActionView层指的是layout开始时就展现在screen上的那些view,在layout完成以后, 所有在ActionViews层的view都会降级为ScrapView. ScarpView指的就是这些old的view, 可以交给adapter进行重用以避免每次都进行不必要的view创建.

  2. mFirstActivePosition: ActionViews中的第一个View在data中的pos.

  3. View[] mActiveViews = new View[0]: ActonView storage, layout开始时展现在screen上的那些View, 每次layout开始时,这个数组就会重新创建, 在layout结束以后,这些View会降级为ScrapView. 在ActionViews中的View是一连串的View, 第一个view在data中的pos存在mFirstActivePosition.

  4. ArrayList[] mScrapViews:ScarpView storage,会被用作传递给Adapter的convertView.注意这是一个Array的数组, 即会有复数个Array, 这么做的原因是因为对于每种View Type,都会有一个Array 作为对应的ScrapView storage

  5. mViewTypeCount&setViewTypeCount(int viewTypeCount): viewTypeCount必须>=1,这个函数做的其实就是初始化了mScrapViews以及对mCurrentScrap的初始化(指向第一个Array):

    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;
    
  6. markChildrenDirty(): 这里将childView标记为dirty其实是调用了childView的forceLayout()函数,意味着下一次layout时,这个childView需要重新measure/layout/draw.

    • 如果viewType只有一种: 将mCurrentScrap中的每个View都调用forceLayout().
    • 如果有复数个viewType:和上面其实一样,挨个处理Array,并且调用其成员的forceLayout().

    mTransientStateViews和mTransientStateViewsById两个数组也会进行dirty标价.

  7. 贴一下(暂态)Transient State在View中的相关注释:

    A view with transient state cannot be trivially rebound from an external data source, such as an adapter binding item views in a list. This may be because the view is performing an animation, tracking user selection of content, or similar

  8. shouldRecycleViewType(int viewType): viewType >= 0(>=0的都视为有效的View type)

  9. clear():清空ScrapView storage:和6的步骤基本一致,对每个View调用removeDetachedView(view, false), 同时还会调用mTransientStateViews和mTransientStateViewsById的clear(). removeDetachedView是ViewGroup的一个函数:

    Finishes the removal of a detached view. This method will dispatch the detached from window event and notify the hierarchy change listener.
    This method is intended to be lightweight and makes no assumptions about whether the parent or child should be redrawn. Proper use of this method will include also making any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
    For example, callers can {@link #post(Runnable) post} a {@link Runnable} which performs a {@link #requestLayout()} on the next frame, after all detach/remove calls are finished, causing layout to be run prior to redrawing the view hierarchy.
    @param child the child to be definitely removed from the view hierarchy
    @param animate if true and the view has an animation, the view is placed in the disappearing views list, otherwise, it is detached from the window.

  10. fillActiveViews(int childCount, int firstActivePosition): 将AbsListView当前的childView都填充到ActionViews storage中. 如果之前创建的mActiveViews的size比childNum小,那么需要重新创建一个childNum大小的mActiveViews. 在填充过程中,会通过childView的layoutParam的ViewType来判断是否是header/footer(不能加入到mActiveViews中,也不会被回收重用):

    // Don't put header or footer views into the scrap heap
    if (lp != null && lp.viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
        // Note:  We do place AdapterView.ITEM_VIEW_TYPE_IGNORE in active views.
        //        However, we will NOT place them into scrap views.
        activeViews[i] = child;
    }
    
  11. getActiveView(int position): 按照data的pos,在ActionViews中查找是否此pos对应的View(所以一开始会先做index = position - mFirstActivePosition), 如果找到了,就返回,并且将mActiveViews中相应位置的引用清空.

  12. getScrapView(int position): 从相应ViewType的Array中取出对应pos的ScrapView(主体是调用retrieveFromScrap(….))

  13. retrieveFromScrap(ArrayList scrapViews, int position): position这里是和view的layoutParams中的scrappedFromPosition做匹配的,如果实在没有匹配的,那就返回Array的最后一个View,View在返回后都会从Array中remove引用. 从这里看,是一种力所能及的retrieve,尽量按照最匹配的(scrappedFromPosition)返回,没有再退而其次(返回最后一个)

  14. addScrapView(View scrap, int position): 将一个View放入到ScrapViews中

    • 首先check view是否有非null的layoutParams(AbsListView.LayoutParams), 如果有,会将view的layoutParam(简称lp)的scrappedFromPosition设为position.
    • 然后获取View的Type(lp的viewType), 如果这个type是不应该recycle,直接返回.(shouldRecycleViewType(): Type >= 0).
    • 会在View上调用dispatchStartTemporaryDetach()
    • 如果View是有暂态的(View.hasTransientState()),也不能将其降级为ScrapView.会根据情况保存在mTransientStateViewsById/mTransientStateViews/mSkippedScrap.
    • 否则,保存在mScrapViews[viewType]的队尾.消除系统管理的暂态(scrap.clearAccessibilityFocus()), 在这一步还会调用mRecyclerListener的onMovedToScrapHeap(scrap).
  15. removeSkippedScrap(): 将所有在mSkippedScrap中的child进行removeDetachedView(…).

  16. scrapActiveViews(…): 和addScrapView(…)的基本规则是一样,一个是加一个,一个是加一群.

  17. pruneScrapViews(): 确保scrapViews的每个Array都不会超过ActiveViews的长度, 并且会再次check mTransientStateViews和mTransientStateViewsById, 从队列中remove已经没有暂态的view(v.hasTransientState()).

  18. reclaimScrapViews(List views): 将ScrapViews中的View全部fill到views中.

  19. setCacheColorHint(int color): 将ScrapViews和ActiveViews中的View的DrawingCacheBackgroundColor都设置为color(setDrawingCacheBackgroundColor(color))

你可能感兴趣的:(Android Adapter机制 源码笔记(6): AbsListView(2))