工作中現在都是使用 RecyclerView,RecyclerView 中,經常使用到的幾個刷新函數如下:
第 1 組
- notifyDataSetChanged():無參,用於通知 Adapter 數據源發生變化並刷新。更新方式是所有 item 整體刷新,是最重的刷新方式
- notifyItemChanged(int position):單參,用於通知在數據源中,位置處於 position 的 item 更新。更新方式是單個 item 整體刷新
- notifyItemInserted(int position):單參,用於通知在數據源中,位置處於 position 的 item 之前有 item 插入,插入之后,position 位置的 item 位置變成了 position + 1。不過應該注意的是
- 該方法使用時,應該首先變化數據源,再調用該方法
- 該方法使用后,並不能真正插入一個 item,還應結合 notifyItemChanged 使用,才能真正插入一條數據。這個方法只是決定了像動畫這些配置。
- notifyItemRemoved(int position):單參,作用和注意事項與 notifyItemInserted 類似,不過一個是增,一個是減。
- notifyItemMoved(int fromPosition, int toPosition):雙參,作用和 notifyItemRemoved、notifyItemInserted 類似,不過此方法對應的含義是移動
第 2 組
- notifyItemRangeRemoved(int positionStart, int itemCount):通知范圍內的 item 被整體刪除了,需要和 notifyItemRangeChanged(int positionStart, int itemCount) 配合使用。
- notifyItemRangeInserted(int positionStart, int itemCount):通知范圍內的 item 整體增加,需要和 notifyItemRangeChanged(int positionStart, int itemCount) 配合使用。
- notifyItemRangeChanged(int positionStart, int itemCount):通知范圍內的 item 變化了
第 3 組
形如 notifyItemChanged(int position, @Nullable Object payload) 等帶上 payload 的方法,其含義都是局部刷新。與三參 onBindViewHolder 結合使用。
遇到的坑
- Android 中沒有提供指定某些 position (位置並不連續) 的 item 更新的方法,我們能做的就是在綁定時進行過濾。
- 部分情況下,可能局部通知刷新並不生效,比如 activity 不在前台,並且不在棧頂時。這時候就需要調用整體刷新的方法,如 notifyDataSetChanged 和 notifyItemChanged。
- 整體刷新方法部分情況下也有可能並不生效。可能的原因有通知刷新的線程不在 UI 線程(網上的回答,真實性待驗證),或者比如 activity 處在后台,處於前台的界面通知其刷新。調用了 notifyItemChanged 方法,此時並不能走到 onBindViewHolder 中,導致界面無法刷新。
- notifyDataSetChanged 方法部分情況下可能也不會生效。比如 activity 處於較深的棧底,處於棧頂的界面通知其刷新,此時調用了 notifyDataSetChanged 方法,但是 adapter 並沒有走到 onBindViewHolder 方法中。此時就需要將更新的數據記錄下來,放入內存或者本地存儲中。在界面從棧頂退回棧底 activity 時,便可以讀取數據,重走綁定流程,保證數據准確。強烈建議將數據存入本地存儲中,這是最穩妥的方式。
- 在 onBindViewHolder 中,每次綁定視圖時,都應考慮 item 復用的問題。雙參的綁定方法不是局部刷新,應視為 item 的整體刷新。在綁定時,應該做到每一個 if 都應該有 else 分支。或者在開始綁定前重置每個視圖的狀態,如清空 TextView 的文本、清空 ImageView 的圖像等等,需要額外注意的一點是,點擊事件也需要做清空處理(本人遇到過 item 的點擊事件復用導致的 BUG,排查了兩天,最終確定的)。