1.Android 大厂面试常见客:RecyclerView 缓存机制
2.Android RecyclerView使用简述
3.RecyclerView详解
4.è°è°RecyclerViewä¸çç¼å
5.RecyclerViewä¸notifyItemRemovedçä¸ä¸ªå
Android 大厂面试常见客:RecyclerView 缓存机制
RecyclerView的码解缓存机制在面试中经常被提及,掌握它有助于提高开发效率。码解
我们将通过具体场景来解析RecyclerView的码解缓存机制,主要包括两个场景:滑动RecyclerView的码解缓存机制和RecyclerView首次加载的缓存机制。
本文主要讲解滑动RecyclerView下的码解缓存机制。
1.缓存层级
背景知识:Recycler类负责回收和复用ViewHolder,码解领袖源码品质站点其主要成员变量负责缓存。码解下面展示部分源码,码解请注意注释(认真阅读注释很重要)。码解
关于缓存层级的码解问题,其实并不重要。码解有人说有三层,码解有人说有四层。码解有人说有三层,码解因为认为自定义层不是码解动漫杀源码RecyclerView实现的,所以不算;也有人认为Scrap不是真正的缓存,所以不算。
从源码来看,我更同意后者,Scrap不算一层缓存。因为在源码中,mCachedViews被称为first-level。日志爬虫源码至于为什么Scrap不算一层,我的理解是:因为这层的只是detach了,并没有remove,所以这层也没有缓存大小的概念,只要符合规则就会加入进去。
2.场景分析:滑动中的RecyclerView缓存机制
通过Android Studio的Profiles工具,我们可以看到调用流程。文艺网站源码入口是ouTouchEvent。
以下表格简要说明上图的流程都在做什么?
通过上述表格,我们知道了最重要的东西就是scrollBy中调用了fill的方法。那么我们来看看fill在做什么?滑出去的View最后去哪里了呢?滑进来的View是怎么来的?(带着这个问题,我们一起来读源码!一定要带着),源码只留下了核心部分。rapidjson源码解析
3.总结
做一个总结,在分析源码前,我们提出了三个问题,现在来看看答案是什么吧。
这里针对以往面试中常见的题,做了些整理归档,该学习手册的内容还在持续更新中,有需要的可以直接点击此处↓↓↓或私信回复:进行获取参考学习!!!
Android RecyclerView使用简述
Android中的RecyclerView是一个功能强大且灵活的视图组件,它能够展示一系列的数据项。与传统的ListView相比,RecyclerView具有更高的性能和更多的灵活性。使用RecyclerView时,需要创建一个Adapter来管理数据和视图,这里的Adapter与ListView的Adapter相似。同时,还需要创建一个LayoutManager来管理RecyclerView中子视图的排列方式,并实现滚动效果。除此之外,RecyclerView还支持添加和移除子视图,以及支持添加和移除动画效果等功能。
提供包括软件源代码、软件需求规格说明书、软件设计报告、软件测试报告、软件用户手册在内的相关文档。
以下是使用RecyclerView的几个简单步骤:
1. 在build.gradle文件中添加RecyclerView的依赖库:
implementation 'androidx.recyclerview:recyclerview:1.1.0'
2. 在布局文件中添加RecyclerView组件:
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
3. 创建RecyclerView的Adapter:
public class MyAdapter extends RecyclerView.Adapter {
private List mData; //数据源
//自定义ViewHolder,用于管理子视图的View对象
static class ViewHolder extends RecyclerView.ViewHolder {
TextView title;
ViewHolder(View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
}
}
//构造方法,传入数据源
public MyAdapter(List data) {
mData = data;
}
//创建ViewHolder对象并返回
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
//绑定数据到ViewHolder中的View对象
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.title.setText(mData.get(position));
}
//返回数据源的长度
@Override
public int getItemCount() {
return mData.size();
}
}
4. 创建RecyclerView的LayoutManager:
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
5. 设置Adapter:
MyAdapter adapter = new MyAdapter(dataList);
recyclerView.setAdapter(adapter);
RecyclerView详解
RecyclerViewä½ä¸ºListViewåGridViewçæ¿ä»£ï¼ä½æ¯åListViewä¸ä¸æ ·çæ¯ï¼RecyclerViewä¸åè´è´£Itemçææ¾çæ¾ç¤ºæ¹é¢çåè½ï¼ææåå¸å±ãç»å¶çæ¹é¢çå·¥ä½é½æåæä¸åçç±»è¿è¡ç®¡çã
RecyclerViewä¸ListViewçä¸åç¹ï¼ä¸»è¦å¨äºä»¥ä¸å 个ç¹æ§ï¼
å¦æä½ æ³ä½¿ç¨RecyclerViewï¼éè¦å以ä¸æä½ï¼
æ们å¯ä»¥ä»ä¸å¾æ´ç´è§çäºè§£å°RecyclerViewçåºæ¬ç»æï¼
RecyclerViewä¸åè´è´£Itemè§å¾çå¸å±åæ¾ç¤ºï¼æ以RecyclerViewä¹æ²¡æ为Itemå¼æ¾OnItemClickçç¹å»äºä»¶ãå¯ä»¥éè¿ä»¥ä¸æ¹å¼è¿è¡ï¼å 为å¨ViewHolderæ们å¯ä»¥æ¿å°æ¯ä¸ªItemçæ ¹å¸å±ï¼æ以å¦ææä»¬ä¸ºæ ¹å¸å±è®¾ç½®åç¬çOnClickçå¬å¹¶å°å ¶å¼æ¾ç»Adapterï¼é£ä¹å°±å¯ä»¥å¨ç»è£ RecyclerViewæ¶å°±è½å¤è®¾ç½®ItemClickListenerï¼åªä¸è¿è¿ä¸ªListenerä¸æ¯è®¾ç½®å°RecyclerViewä¸èæ¯è®¾ç½®å°Adapterã
å¤Itemå¸å±ï¼getItemViewTypeæ¹æ³ï¼ç¨æ³åListView没æä»»ä½åºå«ï¼è¿éè¦æ³¨æçæ¯å½æ°onCreateViewHolder(ViewGroup parent, int viewType)ç第äºä¸ªåæ°å°±æ¯Viewçç±»åï¼å¯ä»¥æ ¹æ®è¿ä¸ªç±»åå¤æå»å建ä¸åitemçViewHolderï¼ä»èå®æå¤Itemå¸å±ã
å¨RecylerViewä¸ï¼Adapteræ®æ¼ç两个è§è²ï¼ä¸æ¯æ ¹æ®ä¸åviewTypeå建ä¸ä¹ç¸åºççitemViewï¼äºæ¯è®¿é®æ°æ®éå并å°æ°æ®ç»å®å°æ£ç¡®çViewä¸ãè¿å°±éè¦æ们å®ç°ä»¥ä¸ä¸¤ä¸ªå½æ°ï¼
å¦å¤æ们è¿éè¦éåå¦ä¸ä¸ªæ¹æ³ï¼åListView-Adapteré£æ ·ï¼åæ ·å°åè¯RecyclerView-Adapterå表Itemsçæ»æ°ï¼
ViewHolderæè¿°RecylerViewä¸æ个ä½ç½®çitemViewåå æ°æ®ä¿¡æ¯ï¼å±äºAdapterçä¸é¨åï¼å ¶å®ç°ç±»é常ç¨äºä¿åfindViewByIdçç»æã 主è¦å ç´ ç»ææï¼
å ³äºViewHolderï¼è¿é主è¦ä»ç»mFlagsï¼
FLAG_BOUNDââViewHolderå·²ç»ç»å®å°æ个ä½ç½®ï¼mPositionãmItemIdãmItemViewTypeé½ææ
FLAG_UPDATEââViewHolderç»å®çView对åºçæ°æ®è¿æ¶éè¦éæ°ç»å®ï¼mPositionãmItemIdè¿æ¯ä¸è´ç
FLAG_INVALIDââViewHolderç»å®çView对åºçæ°æ®æ æï¼éè¦å®å ¨éæ°ç»å®ä¸åçæ°æ®
FLAG_REMOVEDââViewHolder对åºçæ°æ®å·²ç»ä»æ°æ®é移é¤
FLAG_NOT_RECYCLABLEââViewHolderä¸è½å¤ç¨
FLAG_RETURNED_FROM_SCRAPââè¿ä¸ªç¶æçViewHolderä¼å å°scrap list被å¤ç¨ã
FLAG_CHANGEDââViewHolderå 容åçååï¼é常ç¨äºè¡¨ææItemAnimatorå¨ç»
FLAG_IGNOREââViewHolderå®å ¨ç±LayoutManager管çï¼ä¸è½å¤ç¨
FLAG_TMP_DETACHEDââViewHolderä»ç¶RecyclerView临æ¶å离çæ å¿ï¼ä¾¿äºåç»ç§»é¤ææ·»å åæ¥
FLAG_ADAPTER_POSITION_UNKNOWNââViewHolderä¸ç¥é对åºçAdapterçä½ç½®ï¼ç´å°ç»å®å°ä¸ä¸ªæ°ä½ç½®
FLAG_ADAPTER_FULLUPDATEââæ¹æ³addChangePayload(null)è°ç¨æ¶è®¾ç½®
LayoutManager主è¦ä½ç¨æ¯ï¼æµéåææ¾RecyclerViewä¸itemViewï¼ä»¥åå½itemView对ç¨æ·ä¸å¯è§æ¶å¾ªç¯å¤ç¨å¤çã
å½æ们æ³å¨æäºitemä¸å ä¸äºç¹æ®çUIæ¶ï¼å¾å¾é½æ¯å¨itemViewä¸å å¸å±å¥½ï¼ç¶åéè¿è®¾ç½®å¯è§æ§æ¥å³å®åªäºä½ç½®æ¾ç¤ºä¸æ¾ç¤ºãRecyclerViewå°itemViewåè£ é¥°UIåéå¼æ¥ï¼è£ 饰UIå³ItemDecorationï¼ä¸»è¦ç¨äºç»å¶itemé´çåå²çº¿ãé«äº®æè marginçãå ¶æºç å¦ä¸ï¼
è¿å»AdapterViewçitem项æä½å¾å¾æ¯æ²¡æå¨ç»çãç°å¨RecyclerViewçItemAnimator使å¾itemçå¨ç»å®ç°åå¾ç®åèæ ·å¼ä¸°å¯ï¼æ们å¯ä»¥èªå®ä¹item项ä¸åæä½ï¼å¦æ·»å ï¼å é¤ï¼çå¨ç»ææã
Recyclerç¨äºç®¡çå·²ç»åºå¼æä¸RecyclerViewå离çï¼scrapped or detachedï¼item viewï¼ä¾¿äºéç¨ãScrapped viewæä¾éäºRecyclerViewï¼ä½è¢«æ 记为å¯ç§»é¤æå¯å¤ç¨çviewã
LayoutManagerè·åAdapteræä¸é¡¹çViewæ¶ä¼ä½¿ç¨Recyclerãå½å¤ç¨çViewææï¼cleanï¼æ¶ï¼Viewè½ç´æ¥è¢«å¤ç¨ï¼åä¹è¥View失æï¼dirtyï¼æ¶ï¼éè¦éæ°ç»å®Viewã对äºææçViewï¼å¦æä¸ä¸»å¨è°ç¨request layoutï¼åä¸éè¦éæ°æµé大å°å°±è½å¤ç¨ãå¨åæRecyclerçå¤ç¨åçä¹åï¼æ们å äºè§£ä¸å¦ä¸ä¸¤ä¸ªç±»ï¼
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çæ«å°¾é¡¹ã
ViewCacheExtensionæ¯ä¸ä¸ªç±å¼åè æ§å¶çå¯ä»¥ä½ä¸ºViewç¼åç帮å©ç±»ãè°ç¨Recycler.getViewForPosition(int)æ¹æ³è·åViewæ¶ï¼Recyclerå æ£æ¥attached scrapåä¸çº§ç¼åï¼å¦æ没æåæ£æ¥ViewCacheExtension.getViewForPositionAndType(Recycler, int, int)ï¼å¦æ没æåæ£æ¥RecyclerViewPoolã注æï¼Recyclerä¸ä¼å¨è¿ä¸ªç±»ä¸åç¼åViewçæä½ï¼æ¯å¦ç¼åViewå®å ¨ç±å¼åè æ§å¶ã
ç°å¨å¤§å®¶çæäºRecyclerViewPoolåViewCacheExtensionçä½ç¨åï¼ä¸é¢å¼å§ä»ç»Recyclerã å¦ä¸æ¯Recyclerçå ä¸ªå ³é®æååéåæ¹æ³ï¼
è·åæ个ä½ç½®éè¦å±ç¤ºçViewï¼å æ£æ¥æ¯å¦æå¯å¤ç¨çViewï¼æ²¡æåå建æ°View并è¿åãå ·ä½è¿ç¨ä¸ºï¼
注ï¼ä»¥ä¸æ¯æ¥å¹é è¿ç¨é½å¯ä»¥å¹é positionæitemIdï¼å¦ææstableIdï¼ã
è°è°RecyclerViewä¸çç¼å
Androidæ·±å ¥ç解RecyclerViewçç¼åæºå¶
RecyclerViewå¨é¡¹ç®ä¸ç使ç¨å·²ç»å¾æ®éäºï¼å¯ä»¥è¯´æ¯é¡¹ç®ä¸æé«é¢ä½¿ç¨çä¸ä¸ªæ§ä»¶äºãé¤äºå¸å±çµæ´»æ§ã丰å¯çå¨ç»ï¼RecyclerViewè¿æä¼ç§çç¼åæºå¶ï¼æ¬æå°è¯éè¿æºç æ·±å ¥äºè§£ä¸ä¸RecyclerViewä¸çç¼åæºå¶ã
RecyclerViewåæ§è½ä¼åè¦è¯´å¤æä¹å¤æï¼æ¯å¦è¯´å¸å±ä¼åï¼ç¼åï¼é¢å è½½ççãå ¶ä¼åçç¹å¾å¤ï¼å¨è¿äºçä¼¼ç¬ç«çç¹ä¹é´ï¼å ¶å®åå¨ä¸ä¸ªæ¢çº½ï¼Adapterãå 为ææçViewHolderçå建åå 容çç»å®é½éè¦ç»è¿Adaperç两个å½æ°onCreateViewHolderåonBindViewHolderã
å æ¤æ们æ§è½ä¼åçæ¬è´¨å°±æ¯è¦åå°è¿ä¸¤ä¸ªå½æ°çè°ç¨æ¶é´åè°ç¨ç次æ°ãå¦ææ们æ³å¯¹RecyclerViewåæ§è½ä¼åï¼å¿ é¡»æ¸ æ¥çäºè§£å°æ们çæ¯ä¸æ¥æä½èåï¼onCreateViewHolderåonBindViewHolderè°ç¨äºå¤å°æ¬¡ãå æ¤ï¼äºè§£RecyclerViewçç¼åæºå¶æ¯RecyclerViewæ§è½ä¼åçåºç¡ã
为äºç解ç¼åçåºç¨åºæ¯ï¼æ¬æé¦å ä¼ç®åä»ç»ä¸ä¸RecyclerViewçç»å¶åçï¼ç¶åååæå ¶ç¼åå®ç°åçã
RecyclerViewæ»å¨æ¶ä¼è§¦åonTouchEvent#onMoveï¼åæ¶åå¤ç¨ViewHolderå¨è¿éå°±ä¼å¼å§ãæ们ç¥é设置RecyclerViewæ¶éè¦è®¾ç½®LayoutManager,LayoutManagerè´è´£RecyclerViewçå¸å±ï¼å å«å¯¹ItemViewçè·åä¸å¤ç¨ã以LinearLayoutManager为ä¾ï¼å½RecyclerViewéæ°å¸å±æ¶ä¼ä¾æ¬¡æ§è¡ä¸é¢å 个æ¹æ³ï¼
ä¸è¿°çæ´ä¸ªè°ç¨é¾ï¼onLayoutChildren()->fill()->layoutChunk()->next()->getViewForPosition(),getViewForPosition()å³æ¯æ¯ä»RecyclerViewçåæ¶æºå¶å®ç°ç±»Recyclerä¸è·ååéçViewï¼ä¸é¢ä¸»è¦å°±æ¥ä»çè¿ä¸ªRecycler#getViewForPosition()çå®ç°ã
ä¸è¿°é»è¾ç¨æµç¨å¾è¡¨ç¤ºï¼
RecyclerViewå¨Recyleréé¢å®ç°ViewHolderçç¼åï¼Recycleréé¢çå®ç°ç¼åç主è¦å å«ä»¥ä¸5个对象ï¼
public final class Recycler {
final ArrayList mAttachedScrap = new ArrayList<>();
ArrayList mChangedScrap = null;
RecyclerViewå¨è®¾è®¡çæ¶å讲ä¸è¿°5个ç¼å对象å为äº3级ãæ¯æ¬¡å建ViewHolderçæ¶åï¼ä¼æç §ä¼å 级ä¾æ¬¡æ¥è¯¢ç¼åå建ViewHolderãæ¯æ¬¡è®²ViewHolderç¼åå°Recyclerç¼åçæ¶åï¼ä¹ä¼æç §ä¼å 级ä¾æ¬¡ç¼åè¿å»ãä¸çº§ç¼ååå«æ¯ï¼
使ç¨èªå®ä¹ViewCacheExtensionåï¼view离å±åååæ¥ä¸ä¼èµ°onBindViewHolder()æ¹æ³ã
holder.setIsRecyclable(false)ï¼è¿æ ·çè¯æ¯æ¬¡é½ä¼èµ°onCreateViewHolder()åonBindViewHolder()æ¹æ³
1.æååå§åviewHolderï¼æ¾å°ç¼åæ± ä¸
viewPool.putRecycledView(adapter.onCreateViewHolder(recyclerView, 1))
2.æååå§åviewï¼å¨onCreateViewHolderçæ¶åå»åview
3.èªå®ä¹ViewCacheExtension
4.éå½çå¢å cacheSize
4.å ¬ç¨ç¼åæ± ï¼æ¯å¦å¤ä¸ªviewPager+fragmentåºæ¯ä½¿ç¨ï¼æè å ¨å±åå©ç¼åæ± ï¼æè§ç¨æ·ä¸å¤§ã
æ2ä¸åæ³æå¼
第ä¸ç§
第äºç§
ä¸ä¼ï¼å 为prefetchï¼GapWorkerä¸çä¸ä¸ªæ¹æ³ï¼ä¹åmViewCacheMaxä¼åæmRequestedCacheMax + extraCache
æ2ç§æ¹å¼å¯ä»¥è®©ç¼å失æ
第ä¸ç§
recyclerView.setItemViewCacheSize(-1)
第äºç§
recyclerView.setItemViewCacheSize(0)
layoutManager.isItemPrefetchEnabled = false
设置ä¸ç¼ååï¼æ¥åæ»å¨è®©viewè¿å ¥å±å¹ç¦»å¼å±å¹ï¼viewHolderçitemæ¶ä¼å¤æ¬¡èµ°onBindViewHolder()æ¹æ³ã
RecyclerViewä¸notifyItemRemovedçä¸ä¸ªå
碰å°è¿æ ·ä¸ä¸ªéæ±ï¼æä¸ä¸ªå ³æ³¨å表ï¼ç¹å»å表ä¸çå ³æ³¨æé®å¯ä»¥åæ¶å ³æ³¨ã
é¦å å表è¿ééæ©çæ¯RecyclerViewï¼å®ç°èµ·æ¥ä¹è¾ä¸ºç®åï¼å®ç°Adapterç»å®æ°æ®å°±å¯ä»¥äº
ä½æ¯åæ¶å ³æ³¨åéè¦å°è¯¥ç¨æ·ä»å表é移é¤ï¼ä¸ºäºä¸æ´ä½å·æ°ï¼æ以éæ©ä½¿ç¨notifyItemRemovedèä¸æ¯notifyDataSetChangedæ¹æ³ï¼å 为notifyItemRemovedä¸ä¼å é¤adapterä¸æ°æ®éä¸çå®çå ç´ ï¼å æ¤è¿éè¦è°ç¨ dataList.remove(i)
ä½æ¯æµè¯çæ¶ååç°äºä¸ä¸ªé®é¢ï¼
ç¹å»ç¬¬ä¸ä¸ªç¨æ·ï¼æåå é¤ï¼nice.
è¿æ¶ååæ¥ç第äºä¸ªç¨æ·æäºç¬¬ä¸ä¸ªç¨æ·ï¼æç §ä¹åçé»è¾ï¼è¿ä¸ªå°æ¹çpositionåºè¯¥æ¯0ãä½æ¯ï¼ç¹å»ä¹åå é¤çæ¯ç°å¨ç第äºä¸ªç¨æ·ï¼ä¹å°±æ¯è¯´positionæ¯1ã
ç½ä¸æç´¢ååç°ï¼å¨notifyItemRemovedè½ç¶ç§»é¤äºè§å¾ï¼ä½æ¯æ²¡æè¿è¡éæ°bindçè¿ç¨ï¼å æ¤positionè¿æ¯ä¹åçposition,å æ¤éè¦è°ç¨notifyItemRangeChangedæ¹æ³æ¥åè¯åºç¨positionä½ç½®éè¦éæ°è®¡ç®
ä¸é¢ä¸æ®µæ¥èªRecyclerViewæºç ä¸ç注éï¼notifyItemRangeChangedæ¹æ³éè¦ä¸¤ä¸ªåæ°ï¼ç¬¬ä¸ä¸ªæ¥æå®ä»åªéå¼å§æ°æ®è¿è¡äºååï¼ç¬¬äºä¸ªåæ°éè¦æå®æ»å ±ååäºå¤å°ä¸ªæ°æ®ã
å¨æå¼å§æå°çéæ±ä¸ï¼positionStartåºè¯¥çäºè¦å é¤çé£ä¸ªæ°æ®çåæ ï¼itemCountåºè¯¥ä¸ºä»positionStartå¼å§å°æ°æ®å表æåï¼ä½æ¯ä¸ºäºæ¹ä¾¿å°±ç´æ¥å¡«getItemCount()æ´æ°æææ°æ®äº