美文网首页
ListView源码阅读

ListView源码阅读

作者: 坠叶飘香 | 来源:发表于2019-05-09 15:05 被阅读0次

    1. ListView的继承关系

    ListView

    2.setViewTypeCount

    在调用ListView的setAdapter方法时,会调用setViewTypeCount对缓存容器RecycleBin的数据结构进行初始化

    frameworks\base\core\java\android\widget\ListView.java

    (1)应用层调用setAdapter
    public void setAdapter(ListAdapter adapter) {
      if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
        mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);
      } else {
        mAdapter = adapter;
      }
      if (mAdapter != null) {
        mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
      }
    }
    
    (2)初始化RecycleBin的成员变量
    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>();  //mScrapViews 的数组大小跟view type count一致
      }
      mViewTypeCount = viewTypeCount;
      mCurrentScrap = scrapViews[0];
      mScrapViews = scrapViews;
    }
    

    3. layoutChildren

    protected void layoutChildren() {
      if (dataChanged) { //如果数据改变
        for (int i = 0; i < childCount; i++) {
          recycleBin.addScrapView(getChildAt(i), firstPosition+i); //所有的view放入mScrapViews
        }
      } else { //没有改变,放入mActiveViews
        recycleBin.fillActiveViews(childCount, firstPosition);
      }
      detachAllViewsFromParent(); //清除所有子view
      
      fillFromTop(childrenTop);
    
      recycleBin.scrapActiveViews(); //存在于mActiveViews的view移动至mScrapViews
    }
    
    Adapter getView的调用堆栈
    IconListAdapter[72]--> getView                                                        
    | <-- ( android.widget.AbsListView[2490]--> obtainView )    
    | <-- ( android.widget.ListView[2027]--> makeAndAddView )    
    | <-- ( android.widget.ListView[750]--> fillDown )    
    | <-- ( android.widget.ListView[815]--> fillFromTop )    
    | <-- ( android.widget.ListView[1801]--> layoutChildren )    
    | <-- ( android.widget.AbsListView[2278]--> onLayout ) 
    

    4.fillFromTop

    private View fillFromTop(int nextTop) {
      return fillDown(mFirstPosition, nextTop);
    }
    

    5.fillDown

    private View fillDown(int pos, int nextTop) {
      while (nextTop < end && pos < mItemCount) {
        View child = makeAndAddView(pos, nextTop, true, mListPadding.left, selected);
      }
    }
    

    6.makeAndAddView

    private View makeAndAddView(int position, int y, boolean flow, int childrenLeft,
                boolean selected) {
      if (!mDataChanged) {//数据未改变,从mActiveViews获得
        final View activeView = mRecycler.getActiveView(position);
        if (activeView != null) {
          setupChild(activeView, position, y, flow, childrenLeft, selected, true);
          return activeView;
        }
      }
      //数据改变,或者没有获取到,调用obtainView进行获取
      final View child = obtainView(position, mIsScrap);
      setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]);
      return child;
    }
    

    7.obtainView

    View obtainView(int position, boolean[] outMetadata) {
      //1.从mTransientStateViews获取
      final View transientView = mRecycler.getTransientStateView(position);
      if (transientView != null) {
        return transientView;
      }
      //2.从mScrapViews处获取
      final View scrapView = mRecycler.getScrapView(position);
      //这里调用了mAdapter的getView,如果scrapView不为空,就不需要执行inflate方法来生成新view
      final View child = mAdapter.getView(position, scrapView, this);
      returrn child;
    }
    

    8.ListView滑动

    将屏幕之外的view加至mScrapViews
    boolean trackMotionScroll(int deltaY, int incrementalDeltaY) {
      if (down) {
        for (int i = 0; i < childCount; i++) {
          final View child = getChildAt(i);
          if (child.getBottom() >= top) {//view在可见范围
            break;
          } else {
            count++;
            int position = firstPosition + i;
            if (position >= headerViewsCount && position < footerViewsStart) {
              // The view will be rebound to new data, clear any
              // system-managed transient state.
              child.clearAccessibilityFocus();
              mRecycler.addScrapView(child, position); //滑出范围之外,添加到mScrapViews
            }
          }
        }
      } else {
        int bottom = getHeight() - incrementalDeltaY;
        if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
          bottom -= listPadding.bottom;
        }
        for (int i = childCount - 1; i >= 0; i--) {
          final View child = getChildAt(i);
          if (child.getTop() <= bottom) {
            break;
          } else {
            start = i;
            count++;
            int position = firstPosition + i;
            if (position >= headerViewsCount && position < footerViewsStart) {
              // The view will be rebound to new data, clear any
              // system-managed transient state.
              child.clearAccessibilityFocus();
              mRecycler.addScrapView(child, position);//滑出范围之外,添加到mScrapViews
            }
          }
        }
      }
    }
    

    8.retrieveFromScrap

    • id相同
    • 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); //id相同
            if (id == params.itemId) {
              return scrapViews.remove(i);
            }
          } else if (params.scrappedFromPosition == position) { //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;
      }
    }
    

    9.clear

    页面退出时,会执行clear方法,清除缓存的view
    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();
    }
    
    clear的调用堆栈
    ListView--> onDetachedFromWindow                                              
    | <-- ( android.view.View[15673]--> dispatchDetachedFromWindow )    
    | <-- ( android.view.ViewGroup[3187]--> dispatchDetachedFromWindow )    
    | <-- ( android.view.ViewGroup[3179]--> dispatchDetachedFromWindow )    
    | <-- ( android.view.ViewGroup[3179]--> dispatchDetachedFromWindow )    
    | <-- ( android.view.ViewGroup[3179]--> dispatchDetachedFromWindow )    
    | <-- ( android.view.ViewGroup[3179]--> dispatchDetachedFromWindow )    
    | <-- ( android.view.ViewGroup[3179]--> dispatchDetachedFromWindow )    
    | <-- ( android.view.ViewGroup[3179]--> dispatchDetachedFromWindow )    
    | <-- ( android.view.ViewRootImpl[3296]--> dispatchDetachedFromWindow )    
    | <-- ( android.view.ViewRootImpl[6062]--> doDie )    
    | <-- ( android.view.ViewRootImpl[6039]--> die )    
    | <-- ( android.view.WindowManagerGlobal[457]--> removeViewLocked )    
    | <-- ( android.view.WindowManagerGlobal[395]--> removeView )    
    | <-- ( android.view.WindowManagerImpl[126]--> removeViewImmediate )    
    | <-- ( android.app.ActivityThread[4480]--> handleDestroyActivity )
    

    相关文章

      网友评论

          本文标题:ListView源码阅读

          本文链接:https://www.haomeiwen.com/subject/nsmwoqtx.html