RecyclerView性能優化


 

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM