在我們的開發中,RecyclerView是使用非常頻繁的,除了常用的列表展示之外,很多時候我們要根據item的操作進行列表的刷新,比如勾選列表的勾選、刪除或者根據操作動態設置某個item的佈局。這時候,大部分人包括我在內使用的都是這種方式:修改數據源list,然後調用adapter的notifyDataSetChanged()進行刷新。
這種方式是我們經常採用的,在數據量比較小或者大部分的場景下都是適用的。但是這種方式卻是最浪費性能的,只在少部分情況下合適。很多情況下並不合適,比如一個勾選列表,我們進行多選的時候,如果每選一次就進行一次notifyDataSetChanged,相當於因爲針對一個item的操作而刷新整個列表中所有的item,這對於RecyclerView的性能是種損害,也不夠聰明,通過緩存勾選狀態的數據,我們可以使用全局刷新的方式完成想要的結果,但這不是最佳的方式,人都要有點追求,代碼也一樣。我們可以使用局部刷新的方式,爲什麼要進行全局刷新?
而RecyclerView的本身就爲我們提供了局部刷新的方式,在adpter中,有這個方法,它跟我們常用的onBindViewHolder很像,只是多了一個參數,我們就是利用這個參數實現局部刷新的功能,這個參數就是最後面的payloads。
public void onBindViewHolder(VHholder, int position, List<Object> payloads) {
onBindViewHolder(holder, position);
}
因爲這個方法多了一個payloads,而且它會在我們不僅可以利用這個payloads進行邏輯判斷,還能傳參,它是List<Object>類型的數據,這可以說說是我們最方便使用的數據類型,我們可以往裏面放我們的任何類型的數據,從對象到字符串、布爾值、整型或者對象集合等。
而這個帶payloads的onBindViewHolder會在觸發notifyItemChanged(int position, @Nullable Object payload)方法後調用,這個方法我們通過英文也能知道,是刷新指定position的item,並且可以傳遞一個object類型的payloads參數。
拿我實際的項目需求舉例,
如上圖,item的下方有一個按鈕“收起課表”(”展開課表“),我們的需求是在點擊”展開課表“時候進行再接口請求,獲取那些第幾講的數據(別問爲什麼不一次請求完所有數據,就是這個需求),然後課表要有展開的動畫(這個動畫我個人感覺可以再寫個博客,哈哈),這就需要我進行item的局部刷新,那麼如何刷新?
當點擊”展開課表"的接口的時候,回調activity中的接口調用,然後再接口中做完數據的安全判斷後只需要一行代碼courseArrangementListAdapter.notifyItemChanged(unFoldItemPosition, baseResult.getResultData());
notifyItemChanged第一個參數是要刷新的item的position,這個方法的第二個參數,就是onBindViewHolder(VHholder, int position, List<Object> payloads)的payloads,我把課表數據也就是payload傳過去,在onBindViewHolder中如下,通過對payload進行判斷以及取值,就可以只對position=unFoldItemPosition的item進行處理。
我在不帶payloads的onBindViewHolder中處理普通的業務處理,而在帶payloads的onBindViewHolder中進行刷新處理。
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull List<Object> payloads) {
super.onBindViewHolder(holder, position, payloads);
PlanListEntity.RowsBean bean = list.get(position);
if (payloads.isEmpty()) {
LogUtils.d("=========", "onBindViewHolder payload isEmpty ");
onBindViewHolder(holder, position);
} else {
LogUtils.d("=========", "onBindViewHolder payload: " + payloads);
List<CoursePlanTimetableEntity> timetableEntityList = (List<CoursePlanTimetableEntity>) payloads.get(0);
if (timetableEntityList.size() > 0) {
handleTimeView(timetableEntityList, holder);
}
if (holder.tvTimetableAction.getText().toString().equals(context.getString(R.string.fold_timetable))) {
//展示展開課表動畫
showTimetableUnfoldAnimator(timetableEntityList, holder);
} else {
//展示收起課表動畫
showTimetableFoldAnimator(timetableEntityList, holder);
}
}
}
很簡單但是很實用,希望能幫助到看到這篇博客的朋友。