Android RecycledViewPool

01.RecycledViewPool

  • RecycledViewPool

    • RecyclerViewPool用于多个RecyclerView之间共享View。只需要创建一个RecyclerViewPool实例,然后调用RecyclerView的setRecycledViewPool(RecycledViewPool)方法即可。RecyclerView默认会创建一个RecyclerViewPool实例。
    • 下列源码,是我借助于有道词典翻译部分注释内容……
    • 看出mScrap是一个<viewType, List>的映射,mMaxScrap是一个<viewType, maxNum>的映射,这两个成员变量代表可复用View池的基本信息。调用setMaxRecycledViews(int viewType, int max)时,当用于复用的mScrap中viewType对应的ViewHolder个数超过maxNum时,会从列表末尾开始丢弃超过的部分。调用getRecycledView(int viewType)方法时从mScrap中移除并返回viewType对应的List的末尾项
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    public static class RecycledViewPool {
    private static final int DEFAULT_MAX_SCRAP = 5;
    static class ScrapData {
    final ArrayList<ViewHolder> mScrapHeap = new ArrayList<>();
    int mMaxScrap = DEFAULT_MAX_SCRAP;
    long mCreateRunningAverageNs = 0;
    long mBindRunningAverageNs = 0;
    }
    SparseArray<ScrapData> mScrap = new SparseArray<>();
    private int mAttachCount = 0;

    //丢弃所有视图
    public void clear() {
    for (int i = 0; i < mScrap.size(); i++) {
    ScrapData data = mScrap.valueAt(i);
    data.mScrapHeap.clear();
    }
    }

    //设置丢弃前要在池中持有的视图持有人的最大数量
    public void setMaxRecycledViews(int viewType, int max) {
    ScrapData scrapData = getScrapDataForType(viewType);
    scrapData.mMaxScrap = max;
    final ArrayList<ViewHolder> scrapHeap = scrapData.mScrapHeap;
    while (scrapHeap.size() > max) {
    scrapHeap.remove(scrapHeap.size() - 1);
    }
    }

    //返回给定视图类型的RecycledViewPool所持有的当前视图数
    public int getRecycledViewCount(int viewType) {
    return getScrapDataForType(viewType).mScrapHeap.size();
    }

    //从池中获取指定类型的ViewHolder,如果没有指定类型的ViewHolder,则获取{@Codenull}
    @Nullable
    public ViewHolder getRecycledView(int viewType) {
    final ScrapData scrapData = mScrap.get(viewType);
    if (scrapData != null && !scrapData.mScrapHeap.isEmpty()) {
    final ArrayList<ViewHolder> scrapHeap = scrapData.mScrapHeap;
    return scrapHeap.remove(scrapHeap.size() - 1);
    }
    return null;
    }

    //池持有的视图持有者总数
    int size() {
    int count = 0;
    for (int i = 0; i < mScrap.size(); i++) {
    ArrayList<ViewHolder> viewHolders = mScrap.valueAt(i).mScrapHeap;
    if (viewHolders != null) {
    count += viewHolders.size();
    }
    }
    return count;
    }

    //向池中添加一个废视图保存器。
    //如果那个ViewHolder类型的池已经满了,它将立即被丢弃。
    public void putRecycledView(ViewHolder scrap) {
    final int viewType = scrap.getItemViewType();
    final ArrayList<ViewHolder> scrapHeap = getScrapDataForType(viewType).mScrapHeap;
    if (mScrap.get(viewType).mMaxScrap <= scrapHeap.size()) {
    return;
    }
    if (DEBUG && scrapHeap.contains(scrap)) {
    throw new IllegalArgumentException("this scrap item already exists");
    }
    scrap.resetInternal();
    scrapHeap.add(scrap);
    }

    long runningAverage(long oldAverage, long newValue) {
    if (oldAverage == 0) {
    return newValue;
    }
    return (oldAverage / 4 * 3) + (newValue / 4);
    }

    void factorInCreateTime(int viewType, long createTimeNs) {
    ScrapData scrapData = getScrapDataForType(viewType);
    scrapData.mCreateRunningAverageNs = runningAverage(
    scrapData.mCreateRunningAverageNs, createTimeNs);
    }

    void factorInBindTime(int viewType, long bindTimeNs) {
    ScrapData scrapData = getScrapDataForType(viewType);
    scrapData.mBindRunningAverageNs = runningAverage(
    scrapData.mBindRunningAverageNs, bindTimeNs);
    }

    boolean willCreateInTime(int viewType, long approxCurrentNs, long deadlineNs) {
    long expectedDurationNs = getScrapDataForType(viewType).mCreateRunningAverageNs;
    return expectedDurationNs == 0 || (approxCurrentNs + expectedDurationNs < deadlineNs);
    }

    boolean willBindInTime(int viewType, long approxCurrentNs, long deadlineNs) {
    long expectedDurationNs = getScrapDataForType(viewType).mBindRunningAverageNs;
    return expectedDurationNs == 0 || (approxCurrentNs + expectedDurationNs < deadlineNs);
    }

    void attach(Adapter adapter) {
    mAttachCount++;
    }

    void detach() {
    mAttachCount--;
    }
      //分离旧适配器并附加新适配器。如果它只附加了一个适配器,并且新适配器使用与oldAdapter不同的ViewHolder,
      //则RecycledViewPool将清除其缓存。
      void onAdapterChanged(Adapter oldAdapter, Adapter newAdapter,boolean compatibleWithPrevious) {
          if (oldAdapter != null) {
              detach();
          }
          if (!compatibleWithPrevious && mAttachCount == 0) {
              clear();
          }
          if (newAdapter != null) {
              attach(newAdapter);
          }
      }
    
      private ScrapData getScrapDataForType(int viewType) {
          ScrapData scrapData = mScrap.get(viewType);
          if (scrapData == null) {
              scrapData = new ScrapData();
              mScrap.put(viewType, scrapData);
          }
          return scrapData;
      }
    

    }

    1
    2
    3
    4
    5

    - ViewCacheExtension

    - ViewCacheExtension是一个由开发者控制的可以作为View缓存的帮助类。调用Recycler.getViewForPosition(int)方法获取View时,Recycler先检查attachedscrap和一级缓存,如果没有则检查ViewCacheExtension.getViewForPositionAndType(Recycler, int, int),如果没有则检查RecyclerViewPool。注意:Recycler不会在这个类中做缓存View的操作,是否缓存View完全由开发者控制。


    public abstract static class ViewCacheExtension {
    abstract public View getViewForPositionAndType(Recycler recycler, int position, int type);
    }
    ```