Android中的RecyclerView詳解
RecyclerView是什麼
官方解釋如下:A flexible view for providing a limited window into a large data set.
意思就是說在一個有限的視窗中顯示大量的資料集.

回顧一下以前我們使用的ListView
ListView的侷限
- 只有縱向列表一種佈局
- 沒有支援動畫的API
- 介面設計和系統不一致
- setOnItemClickListener()
- setOnItemLongClickListener()
- setSelection()
- 沒有強制實現ViewHolder
- 效能不如RecyclerView
使用RecyclerView的優勢
-
預設支援Linear, Grid, Staggered Grid三種佈局
-
友好的ItemAnimator動畫API
-
強制實現ViewHolder
-
解耦架構設計
-
相比 ListView更好的效能
RecyclerView支援的佈局

RecyclerView Demo
ViewHolder究竟是什麼?
ListView中getView暴露的問題
@Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.list_view_item, parent, false); } /** * 下面的程式碼無論在convertView是否為null都會執行 */ ImageView avatar = convertView.findViewById(R.id.user_avatar); TextView name = convertView.findViewById(R.id.user_name); TextView title = convertView.findViewById(R.id.user_title); User user = getItem(position); Glide.with(parent.getContext()).load(user.avatar).into(avatar); name.setText(user.name); title.setText(user.title); return convertView; }
上面的程式碼在執行getView,每次都會去findViewById,如果view個數比較多findViewById次數就會增多,這樣顯然會降低效率. ViewHolder的出現就是為了儲存View引用的容器類,減少重複findViewById次數,下面來看看用ViewHolder如何優化上面的程式碼.
public View getView(int position, View convertView, ViewGroup parent) { UserViewHolder holder; if (convertView == null) { convertView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.list_view_item, parent, false); holder = new UserViewHolder(convertView); holder.avater = convertView.findViewById(R.id.user_avatar); holder.name = convertView.findViewById(R.id.user_name); holder.title = convertView.findViewById(R.id.user_title); convertView.setTag(holder); } else { holder = (UserViewHolder)convertView.getTag(); } /** * 下面的程式碼無論在convertView是否為null都會執行 */ ImageView avatar = convertView.findViewById(R.id.user_avatar); TextView name = convertView.findViewById(R.id.user_name); TextView title = convertView.findViewById(R.id.user_title); User user = getItem(position); holder.title.setText(user.title); holder.name.setText(user.name); Glide.with(parent.getContext()).load(user.avatar).into(holder.avater); return convertView; }
ViewHolder和View的對應關係

RecyclerView快取機制
在講解RecyclerView快取機制之前先來看看ListView的快取機制,它的快取機制比RecyclerView簡單,但是大體思想是一樣的.

對應到螢幕上

RecyclerView的快取機制

Scrap: 在螢幕內可視的Item。
Cache: 在螢幕外的Item
ViewCacheExtension : 使用者自定義的快取策略
RecycledViewPool : 被廢棄的itemview,髒資料,需要重新onBindViewHolder.
在螢幕上的

這裡需要注意的是這個Cache,它雖然是快取,但是它快取效果和Scarp效果是一樣的。例如你的Cache是2,你上滑動出去後,下滑回來的兩個item是不會再進行onBindViewHolder的.
這裡另外提一點的是:
列表中item/廣告的impression統計.
- ListView通過getView統計
- RecycleView通過onBindViewHolder()統計?可能錯誤!
- 通過onViewAttachedToWindow()統計
你可能不知道的RecyclerView效能優化策略
第一點
不要在onBindViewHolder中設定監聽器,在onCreateViewHolder中設定監聽器.
第二點
LinearLayoutManager.setInitialPrefetchitemCount()
- 使用者滑動到橫向滑動的item RecyclerView的時候,由於需要建立更復雜的RecyclerView以及多個子view,可能會導致頁面卡頓
- 由於RenderThread的存在,RecyclerView會進行prefetch
- LinearLayoutManager.setInitialPrefetchItemCount(橫向列表初次顯示可見的item個數)
-- 只有LinearLayoutManager有這個API
-- 只有潛逃在內部的RecyclerView才會生效.
第三點
RecyclerView.setHasFixedSize()

什麼時候用?
如果Adapter的資料變化不會導致RecyclerView的大小變化就可以用
RecyclerView.setHasFixedSize(true)
第四點
多個RectclerView共用RecycledViewPool.

第五點
使用DiffUtil
ItemDecoration的作用.
最後
在現在這個金三銀四的面試季,我自己在網上也蒐集了很多資料做成了文件和架構視訊資料免費分享給大家【 包括高階UI、效能優化、架構師課程、NDK、Kotlin、混合式開發(ReactNative+Weex)、Flutter等架構技術資料 】,希望能幫助到您面試前的複習且找到一個好的工作,也節省大家在網上搜索資料的時間來學習。
資料獲取方式:加入Android架構交流QQ群聊:513088520 ,進群即領取資料!!!
點選連結加入群聊【Android移動架構總群】:加入群聊

資料大全