1、數據處理與視圖加載分離
bindViewHolder方法是在UI線程進行的,此方法不能耗時操作,不然將會影響滑動流暢性。
優化前: class Task { Date dateDue; String title; String description; // getters and setters here } class MyRecyclerView.Adapter extends RecyclerView.Adapter { static final TODAYS_DATE = new Date(); static final DATE_FORMAT = new SimpleDateFormat("MM dd, yyyy"); public onBindViewHolder(Task.ViewHolder tvh, int position) { Task task = getItem(position); if (TODAYS_DATE.compareTo(task.dateDue) > 0) { tvh.backgroundView.setColor(Color.GREEN); } else { tvh.backgroundView.setColor(Color.RED); } String dueDateFormatted = DATE_FORMAT.format(task.getDateDue()); tvh.dateTextView.setDate(dueDateFormatted); } }
上面的onBindViewHolder
方法中進行了日期的比較和日期的格式化,這個是很耗時的,在onBindViewHolder
方法中,應該只是將數據set
到視圖中,而不應進行業務的處理。
優化后: public class TaskViewModel { int overdueColor; String dateDue;
// getters and setters } public onBindViewHolder(Task.ViewHolder tvh, int position) { TaskViewModel taskViewModel = getItem(position); tvh.backgroundView.setColor(taskViewModel.getOverdueColor()); tvh.dateTextView.setDate(taskViewModel.getDateDue()); }
2、數據優化
1. 分頁加載遠端數據,對拉取的遠端數據進行緩存,提高二次加載速度; 2. 對於新增或刪除數據通過DiffUtil,來進行局部數據刷新,而不是一味的全局刷新數據
DiffUtil是support包下新增的一個工具類,用來判斷新數據和舊數據的差別,從而進行局部刷新。
DiffUtil的使用,在原來調用mAdapter.notifyDataSetChanged()的地方:
// mAdapter.notifyDataSetChanged() DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffCallBack(oldDatas, newDatas), true); diffResult.dispatchUpdatesTo(mAdapter);
DiffUtil最終是調用Adapter的下面幾個方法來進行局部刷新:
mAdapter.notifyItemRangeInserted(position, count);
mAdapter.notifyItemRangeRemoved(position, count);
mAdapter.notifyItemMoved(fromPosition, toPosition);
mAdapter.notifyItemRangeChanged(position, count, payload);
3、布局優化
減少xml文件inflate時間
xml文件包括:layout、drawable的xml,xml文件inflate出ItemView是通過耗時的IO操作。可以使用代碼去生成布局,即new View()的方式。這種方式是比較麻煩,但是在布局太過復雜,或對性能要求比較高的時候可以使用。
減少View對象的創建
一個稍微復雜的 Item 會包含大量的 View,而大量的 View 的創建也會消耗大量時間,所以要盡可能簡化 ItemView;設計 ItemType 時,對多 ViewType 能夠共用的部分盡量設計成自定義 View,減少 View 的構造和嵌套。
4、數據Prefatch預取
升級 RecycleView 版本到 25.1.0 (>=21)及以上使用 Prefetch 功能 1)setItemPrefatchEnable(false)可關閉預取功能 2)嵌套時且使用的是LinearLayoutManager,子RecyclerView可通過setInitialPrefatchItemCount設置預取個數 3)二級緩存時不需要重新綁定
5、加大RecyclerView緩存
recyclerView.setItemViewCacheSize(20); recyclerView.setDrawingCacheEnabled(true); recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
通過 RecycleView.setItemViewCacheSize(size); 來加大 RecyclerView 的緩存,用空間換時間來提高滾動的流暢性。
6、item設置高度固定
item高度是固定的話,可以使用RecyclerView.setHasFixedSize(true);來避免requestLayout浪費資源。
7、通過重寫 RecyclerView.onViewRecycled(holder) 來回收資源
8、對 TextView 使用 String.toUpperCase 來替代 android:textAllCaps="true"
使用textAllCaps會導致申請更多內存,當為true時,TextView內部都會創建一個新的Transformnation來處理字符串
9、共用RecycledViewPool
如果多個 RecycledView 的 Adapter 是一樣的,比如嵌套的 RecyclerView 中存在一樣的 Adapter,可以通過設置 RecyclerView.setRecycledViewPool(pool); 來共用一個 RecycledViewPool。
10、增加RecyclerView預留的額外空間
額外空間:顯示范圍之外,應該額外緩存的空間 new LinearLayoutManager(this) { @Override protected int getExtraLayoutSpace(RecyclerView.State state) { return size; } };
11、優化滑動操作
設置RecyclerView.addOnScrollListener();來在滑動過程中停止加載的操作。
12、減少ItemView監聽器的創建
對 ItemView 設置監聽器,不要對每個 Item 都調用 addXxListener,應該大家公用一個 XxListener,根據 ID 來進行不同的操作,優化了對象的頻繁創建帶來的資源消耗。
13、處理刷新閃爍
用notifyDataSetChange時,適配器不知道整個數據集中的那些內容以及存在,再重新匹配ViewHolder時會花生閃爍。 設置adapter.setHasStableIds(true),並重寫getItemId()來給每個Item一個唯一的ID