new ArrayList<ViewHolder>(); int mViewCacheMax = DEFAULT_CACHE_SIZE; static final int DEFAULT_CACHE_SIZE = 2; ... } View Cache Session Android Team 1. mCachedViews에 ViewHolder 캐싱 2. 기본 cache size : 2 3. position 기반의 캐싱 및 탐색 4. Queue와 유사하게 FIFO로 저장됨
= mAttachedScrap.size(); ... // Search in our first-level recycled view cache. final int cacheSize = mCachedViews.size(); for (int i = 0; i < cacheSize; i++) { final ViewHolder holder = mCachedViews.get(i); // invalid view holders may be in cache if adapter has stable ids as they can be // retrieved via getScrapOrCachedViewForId if (!holder.isInvalid() && holder.getLayoutPosition() == position && !holder.isAttachedToTransitionOverlay()) { if (!dryRun) { mCachedViews.remove(i); } ... return holder; } } return null; }
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<>(); ... } RecycledViewPool Session Android Team 1. RecycledViewPool 클래스에서 관리 2. 기본 pool size : 5 3. 별도의 Heap을 가짐 4. ViewType 기반의 캐싱 및 탐색 5. Stack과 유사하게 LIFO로 저장됨
if (holder == null) { final int offsetPosition = mAdapterHelper.findPositionOffset(position); final int type = mAdapter.getItemViewType(offsetPosition); ... if (holder == null) { // fallback to pool holder = getRecycledViewPool().getRecycledView(type); ... } ... } ... return holder; } RecyclerView.Recycler#tryGetViewHolderForPositionByDeadline 1. view cache 탐색 2. RecycledViewPool 탐색 3. 7번까지 찾지 못했다면 새로운 ViewHolder 생성 (onCreateViewHolder) 4. ViewHolder에 바인딩이 필요하다면 바인딩 실행 (onBindViewHolder)
클릭 이벤트는 어디서 처리하는 것이 좋은가? 2. 중첩 스크롤 처리는 어떻게 하는 것이 좋은가? (feat. NestedScrollView) 3. Multi ViewType 부터 ConcatAdapter까지 4. Payload 관련 + NotifyDataSetChanged를 지양하는 이유 + DiffUtil