寫的程序中發現有人寫的也很完整,可以去看看 RecyclerView 和 ListView 使用對比分析, 2021/02/24補充
1. RecycleView的簡單使用
主要作業是繼承RecycleView.Adapter,并重寫
1.RecyclerView.ViewHolder
2.onCreateViewHolder()用于創建ViewHolder實體,并把加載的布局傳入到建構式去,再把ViewHolder實體回傳,
3.onBindViewHolder()則是用于對子項的資料進行賦值,會在每個子項被滾動到螢屏內時執行,position得到當前項的Fruit實體,
LayoutManager用于指定RecyclerView的布局方式,LinearLayoutManager指的是線性布局
一般使用方式:
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
FruitAdapter adapter = new FruitAdapter(fruitList); recyclerView.setAdapter(adapter);
通過呼叫setOrientation()把布局的排列方向改為水平排列,
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
除了LinearLayoutManager,RecyclerView還提供了GridLayoutManager(網格布局)和StaggeredGridLayoutManager(瀑布流布局)
2. RecycleView和ListView的區別(10點,不認可的歡迎評論)
可以參考: https://www.cnblogs.com/chen-ying/p/12386712.html
>還是自己也整理下吧
(1)基礎使用
ListView需要使用自定義的ViewHolder和ConvertView來完成復用優化作業.(setTag && getTag)
RecycleView中的RecycleView.ViewHolder已經封裝了復用,不需要自己優化了,
需要重寫的方法肯定是不同的,翻看原始碼即知,(getView Vs onCreateViewHolder && onBindViewHolder)
(2)布局效果
RecycleView 只負責管理視圖的重復利用,然后將布局的管理全權交給了 LayoutManager.
LayoutManager 是一個抽象類,系統已經為我們提供了三個相關的實作: LinearLayoutManager(線性布局效果)、GridLayoutManager(網格布局效果)、 StaggeredGridLayoutManager(瀑布流布局效果), RecyclerView 默認就能支持 線性布局、 網格布局、瀑布流布局 三種 ,通過配置和切換 LayoutManager 就可以獲得不同的布局效果,所以 如果想自定義出更多布局效果,可以繼承重寫自己的LayoutManager,通過LayoutManager還可以 設定滾動方向、獲取Item的位置
(3)空資料視圖處理
ListView現有提供了setEmptyView方法,詳細使用可參考: android筆記之ListView的setEmptyView方法 ,核心內容是在ListView同級設定空資料需要展示的視圖,交由ListView進行資料是否為null的判斷,從而設定empty的visible,
RecycleView沒有setEmptyView方法,需要自己實作,可以參考: RecyclerView添加EmptyView ,核心內容是在重寫的RecycleView中重寫AdapterDataObserver并注冊它, 在資料變化時判斷資料是否為null,從而設定RecycleView本身以及EmptyView的顯示和隱藏,
(4)HeaderView 與 FooterView
ListView中可以通過addHeaderView() 與 addFooterView()來添加頭部item與底部item,來當我們需要實作下拉重繪或者上拉加載的情況;而且這兩個API不會影響Adapter的撰寫,
使用時需要注意一些東西: addHeaderView與addFooterView
RecycleView沒有這兩個API,但可以在Adapter中撰寫,根據ViewHolder的Type與View來實作自己的Header,Footter與普通的item,但是這樣就會影響到Adapter,改動較大,(這是常見的作法)
可以參照: RecyclerView頭部尾部添加方法,實作原理是追加Header&Footer兩種View,并設定三種型別(TYPE_HEAD&TYPE_FOOTER&TYPE_NORMAL),復寫getItemViewType和修改getItemCount&onCreateViewHolder&onBindViewHolder,
onCreateViewHolder(ViewGroup parent, int viewType)
該方法中的viewType就是通過getItemViewType設定的, 詳細可參照鏈接寫個demo嘗試下,
(5)影片效果
ListView沒有為item提供影片,需要自己實作,具體可以參照:listview添加item影片
整體設定影片:
listView.setLayoutAnimation(getAnimationController());
RecycleView有為item提供默認影片: DefaultItemAnimator,在使用RecycleView時進行增刪的時候,會很明顯看到影片效果, 若是想深入研究或自定義影片,可以參照: 自定義DefaultItemAnimator
(6)區域重繪
ListView的重繪notifyDataSetChanged,它會重繪所有item,所以不能應用于區域重繪,問題來了,ListView如何區域重繪呢?
a. 官方推薦方式:
public View getView(int position, View convertView, ViewGroup parent) {
// 獲取到指定位置的View,主動呼叫getView方法
View view = listView.getChildAt(position- listView.getFirstVisiblePosition());
getView(position, view, listView);
b.大眾的方式: (在Adapter中添加一個區域重繪的方法)
public void updateItem(ListView mListView, int posi) {
if (mListView != null) {
// 獲取第一個顯示的item
int visiblePos = mListView.getFirstVisiblePosition();
// 計算出當前選中的position和第一個的差,也就是當前在螢屏中的item位置
int offset = posi - visiblePos;
int lenth = mListView.getChildCount();
// 只有在可見區域才更新,因為不在可見區域得不到Tag,會出現空指標,所以這是必須有的一個步驟
if ((offset < 0) || (offset >= lenth)) return;
View convertView = mListView.getChildAt(offset);
ViewHolder viewHolder = (ViewHolder) convertView.getTag();
// 已知view||viewholder,就可以進行自己想要的資料重繪
// Tips:別忘了資料的更新
}
}
RecycleView提供了區域重繪的方法: notifyItemChanged,原始碼如下.
public final void notifyItemChanged(int position) {
mObservable.notifyItemRangeChanged(position, 1);
}
(7)ItemTouchHelper(拖拽&側滑的實作)
ItemTouchHelper 是幫助Recycleview實作拖拽和側滑的工具類,
// 1. 繼承并重寫 ItemTouchHelper.Callback
public class ItemTouchHelperCallback extends ItemTouchHelper.Callback{
// 重寫getMovementFlags()方法來指定可以支持的拖放和滑動的方向使用
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
mRecyclerAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mRecyclerAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
}
// 2. 建立與RecycleView的鏈接
ItemTouchHelper mItemTouchHelper = new ItemTouchHelper(new ItemTouchHelperCallback());
mItemTouchHelper.attachToRecyclerView(mRecyclerView);
// 補充說明
// onItemMove中主要做notifyItemMoved(fromPosition, toPosition); 以及資料的洗掉
以上可以輕松實作Recycleview的側滑和拖拽的影片效果,
但是ListView沒有提供此類方法,實作ListView的側滑和拖拽可以參考: ListView的拖動和側滑實作 (WindowManager實作拖動, ViewDragHelper實作側滑), 寫的比較清晰,大家可以嘗試下,
(8)點擊事件
ListView中提供了setOnItemClickListener、 setOnItemLongClickListener、setOnItemSelectedListener等方法,但要考慮設定了header和footer后的陣列越界問題,
Recycleview沒有提供這些方法,因此需要通過viewHolder去給子項設定具體的監聽,(很常見,就不貼什么代碼了)
(9)嵌套滾動機制
Android 觸摸事件分發機制:Touch 事件在進行分發的時候,由父 View 向它的子 View 傳遞,一旦某個子 View 開始接收進行處理,那么接下來所有事件都將由這個 View 來進行處理,它的 ViewGroup 將不會再接收到這些事件,直到下一次手指按下,而嵌套滾動機制(NestedScrolling)就是為了彌補這一機制的不足,為了讓子 View 能和父 View 同時處理一個 Touch 事件,
CollapsingToolbarLayout 這種需要嵌套滾動的機制才能達到效果的控制元件,那么 首選RecyclerView (Recycleview實作了NestedScrollingChild介面),因為 ListView無效,同樣的,ScrollView 也是不支持嵌套滾動機制,但是你可以使用 NestedScrollView ,
(10)復用機制
ListView快取機制
RecycleBin機制,RecycleBin定義在AbsListView當中,其中使用View[] mActiveViews存盤View,是螢屏當中正在使用的View,mActiveViews中存盤的View只能被獲取一次;ArrayList[] mScrapViews和ArrayList mCurrentScrap則是用于存盤移動出螢屏后被廢棄的View,當getView方法在配接器中被呼叫的時候,其中傳入的convertView如果不為空,就是從廢棄的View當中獲得的,
RecyclerView快取機制
Scrap和Cache分別是通過position去找ViewHolder可以直接復用;
在RecyclerView當中也并不是每次都重新創建ViewHolder物件,不是每次都重新系結ViewHolder資料,而是通過Recycler來獲得下一個ViewHolder,
RecyclerView使用Recycler管理快取ViewHolder,對于不同狀態的ViewHolder存盤在了不同的集合中,RecyclerView有四級快取,分別是ArrayList mAttachedScrap、ArrayList mCachedViews、ViewCacheExtension mViewCacheExtension 和 RecycledViewPool mRecyclerPool,快取的物件是ViewHolder,
而從RecycledViewPool 中復用的ViewHolder需要重新系結資料,并且復用的ViewHolder只能復用于ViewType相同的表項,因為RecycledViewPool 對ViewHolder是按照ViewType分類存盤的,RecycledViewPool通過type來獲取ViewHolder,獲取的ViewHolder是個全新,需要重新系結資料;ViewCacheExtension自定義快取,目前來說應用場景比較少卻需慎用;從mCachedViews中復用ViewHolder只能復用于指定位置的item;而從mAttachedScrap復用的ViewHolder不需要重新創建也不需要重新系結資料,
如果四個層級的快取都沒有命中,才會重新創建ViewHolder物件并且系結,
3. RecycleView和ListView的快取原理詳解
第二章節大致介紹了兩者的快取機制,
詳細的原始碼分析可以參照: 明日補充,一時找不到之前看的鏈接了,看中了人家的流程圖,(實在是沒有太多精力細細的肝原始碼了)
4. RecycleView如何優化?
可以參考: https://juejin.cn/post/6844903661726859271#heading-4
想認真的理解并掌握所有的區別以及原理,怕不是那么容易的事情喲,
知道的越多,不知道的越多,
參考文章:
https://www.cnblogs.com/chen-ying/p/12386712.html
https://www.jianshu.com/p/3e9aa4bdaefd
https://juejin.cn/post/6844903661726859271#heading-4
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/263478.html
標籤:其他
上一篇:Airtest學習(一)
