提高Android RecyclerView性能的技巧

一、使用ViewHolder提升性能

在Android 5.0以前,RecyclerView使用ViewHolder來重用布局並減少內存消耗。ViewHolder是一個包含視圖組件的容器,可以提高視圖重用的效率。我們可以通過繼承RecyclerView.ViewHolder來創建ViewHolder。

class MyViewHolder extends RecyclerView.ViewHolder {
    TextView name;
    TextView age;
    public MyViewHolder(View view) {
        super(view);
        name = (TextView) view.findViewById(R.id.name);
        age = (TextView) view.findViewById(R.id.age);
    }
}

ViewHolder的使用可以減少inflate布局的次數,從而提高RecyclerView的性能。在onBindViewHolder()方法中,我們可以將數據綁定到ViewHolder中的視圖組件上。

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
    holder.name.setText(mData.get(position).getName());
    holder.age.setText(mData.get(position).getAge());
}

二、使用DiffUtil優化數據更新

RecyclerView經常需要更新數據,而DiffUtil可以提高數據更新的效率。DiffUtil是一個工具類,用於計算兩個數據集之間的差異。在數據更新時,我們可以使用DiffUtil來計算數據集差異,從而只更新變化的部分,減少不必要的重繪和動畫效果。

class MyDiffCallback extends DiffUtil.Callback {
    private List oldList;
    private List newList;
    public MyDiffCallback(List oldList, List newList) {
        this.oldList = oldList;
        this.newList = newList;
    }
    @Override
    public int getOldListSize() {
        return oldList.size();
    }
    @Override
    public int getNewListSize() {
        return newList.size();
    }
    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        return oldList.get(oldItemPosition).getId() == newList.get(newItemPosition).getId();
    }
    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        MyData oldData = oldList.get(oldItemPosition);
        MyData newData = newList.get(newItemPosition);
        return oldData.getName().equals(newData.getName()) && oldData.getAge() == newData.getAge();
    }
}

DiffUtil需要實現四個回調方法,getOldListSize()和getNewListSize()返回舊數據集和新數據集的大小,areItemsTheSame()判斷兩個數據是否為同一個item,areContentsTheSame()判斷同一位置的兩條數據是否內容相同。

在數據更新時,我們需要在新數據集合成前使用DiffUtil計算差異,將差異應用到適配器中並更新RecyclerView。

MyDiffCallback diffCallback = new MyDiffCallback(mData, newData);
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);
mData = newData;
diffResult.dispatchUpdatesTo(this);

三、使用ItemDecoration美化界面和提升性能

ItemDecoration可以為RecyclerView添加自定義的分割線、顏色、邊距等,使界面更加美觀,同時也可以提高RecyclerView的性能。我們通常使用RecyclerView.ItemDecoration來創建ItemDecoration。

public class MyItemDecoration extends RecyclerView.ItemDecoration {
    private int mDividerHeight;
    private Paint mPaint;
    public MyItemDecoration(int dividerHeight, int dividerColor) {
        mDividerHeight = dividerHeight;
        mPaint = new Paint();
        mPaint.setColor(dividerColor);
        mPaint.setStyle(Paint.Style.FILL);
    }
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        outRect.bottom = mDividerHeight;
    }
    @Override
    public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();
        for (int i = 0; i < parent.getChildCount() - 1; i++) {
            View child = parent.getChildAt(i);
            float top = child.getBottom();
            canvas.drawRect(left, top, right, top + mDividerHeight, mPaint);
        }
    }
}

在RecyclerView中添加ItemDecoration。

MyItemDecoration itemDecoration = new MyItemDecoration(dp2px(1), Color.GRAY);
recyclerView.addItemDecoration(itemDecoration);

四、使用RecyclerView滑動監聽減少內存消耗

RecyclerView在滑動時,會大量的創建和銷毀視圖,如果在滑動過程中同時處理複雜的數據操作,會導致卡頓或者OOM。因此,我們可以在RecyclerView滑動時停止載入圖片或者其他佔用內存的操作,從而減少內存消耗,提高滑動性能。我們可以通過RecyclerView的addOnScrollListener()監聽RecyclerView的滑動狀態。

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        switch (newState) {
            case RecyclerView.SCROLL_STATE_IDLE:
                //滑動停止,可以執行數據載入等其他操作
                break;
            case RecyclerView.SCROLL_STATE_DRAGGING:
                //手指觸摸滑動中,應停止數據載入等流操作
                break;
            case RecyclerView.SCROLL_STATE_SETTLING:
                //慣性滑動中,應停止數據載入等流操作
                break;
        }
    }
});

五、使用LayoutManager優化布局

LayoutManager是RecyclerView中布局管理器的基類,可以用於控制RecyclerView中子View的布局方式。使用LayoutManager可以實現多種複雜的布局,並且可以優化RecyclerView的性能。下面介紹幾種常見的LayoutManager。

1. LinearLayoutManager

LinearLayoutManager是RecyclerView默認的布局管理器,控制子View的排列方向,有三種排列方式:VERTICAL、HORIZONTAL、Horizontal.VERTICAL。

LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);

2. GridLayoutManager

GridLayoutManager可以將子View排列成網格形式。可以通過GridLayoutManager的構造函數來控制列數。

GridLayoutManager layoutManager = new GridLayoutManager(this, 2);
recyclerView.setLayoutManager(layoutManager);

3. StaggeredGridLayoutManager

StaggeredGridLayoutManager可以將子View排列成不規則的網格形式。可以通過StaggeredGridLayoutManager的構造函數來控制列數和方向。

StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);

完整代碼示例

public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private List mData;
    private MyAdapter mAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = findViewById(R.id.recyclerView);
        initData();
        mAdapter = new MyAdapter(mData);
        recyclerView.setAdapter(mAdapter);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);
        MyItemDecoration itemDecoration = new MyItemDecoration(dp2px(1), Color.GRAY);
        recyclerView.addItemDecoration(itemDecoration);
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                switch (newState) {
                    case RecyclerView.SCROLL_STATE_IDLE:
                        //滑動停止,可以執行數據載入等其他操作
                        break;
                    case RecyclerView.SCROLL_STATE_DRAGGING:
                        //手指觸摸滑動中,應停止數據載入等流操作
                        break;
                    case RecyclerView.SCROLL_STATE_SETTLING:
                        //慣性滑動中,應停止數據載入等流操作
                        break;
                }
            }
        });
    }
    private void initData() {
        mData = new ArrayList();
        mData.add(new MyData(1, "張三", 18));
        mData.add(new MyData(2, "李四", 20));
        mData.add(new MyData(3, "王五", 22));
        mData.add(new MyData(4, "趙六", 21));
    }
    public int dp2px(float dpValue) {
        final float scale = getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
    class MyAdapter extends RecyclerView.Adapter {
        private List mData;
        public MyAdapter(List data) {
            mData = data;
        }
        @NonNull
        @Override
        public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
            MyViewHolder viewHolder = new MyViewHolder(view);
            return viewHolder;
        }
        @Override
        public void onBindViewHolder(MyViewHolder holder, int position) {
            holder.name.setText(mData.get(position).getName());
            holder.age.setText(mData.get(position).getAge());
        }
        @Override
        public int getItemCount() {
            return mData.size();
        }
    }
    class MyViewHolder extends RecyclerView.ViewHolder {
        TextView name;
        TextView age;
        public MyViewHolder(View view) {
            super(view);
            name = (TextView) view.findViewById(R.id.name);
            age = (TextView) view.findViewById(R.id.age);
        }
    }
    class MyData {
        private int id;
        private String name;
        private int age;
        public MyData(int id, String name, int age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }
        public int getId() {
            return id;
        }
        public String getName() {
            return name;
        }
        public int getAge() {
            return age;
        }
    }
    class MyItemDecoration extends RecyclerView.ItemDecoration {
        private int mDividerHeight;
        private Paint mPaint;
        public MyItemDecoration(int dividerHeight, int dividerColor) {
            mDividerHeight = dividerHeight;
            mPaint = new Paint();
            mPaint.setColor(dividerColor);
            mPaint.setStyle(Paint.Style.FILL);
        }
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            outRect.bottom = mDividerHeight;
        }
        @Override
        public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
            int left = parent.getPaddingLeft();
            int right = parent.getWidth() - parent.getPaddingRight();
            for (int i = 0; i < parent.getChildCount() - 1; i++) {
                View child = parent.getChildAt(i);
                float top = child.getBottom();
                canvas.drawRect(left, top, right, top + mDividerHeight, mPaint);
            }
        }
    }
    class MyDiffCallback extends DiffUtil.Callback {
        private List oldList;
        private List newList;
        public MyDiffCallback(List oldList, List newList) {
            this.oldList = oldList;
            this.newList = newList;
        }
        @Override
        public int getOldListSize() {
            return oldList.size();
        }
        @Override
        public int getNewListSize() {
            return newList.size();
        }
        @Override
        public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
            return oldList.get(oldItemPosition).getId() == newList.get(newItemPosition).getId();
        }
        @Override
        public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
            MyData oldData = oldList.get(oldItemPosition);
            MyData newData = newList.get(newItemPosition);
            return oldData.getName().equals(newData.getName()) && oldData.getAge() == newData.getAge();
        }
    }
}

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/259389.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-15 16:28
下一篇 2024-12-15 16:28

相關推薦

  • 使用vscode建立UML圖的實踐和技巧

    本文將重點介紹在使用vscode在軟體開發中如何建立UML圖,並且給出操作交互和技巧的指導。 一、概述 在軟體開發中,UML圖是必不可少的重要工具之一。它為軟體架構和各種設計模式的…

    編程 2025-04-29
  • 如何優化 Git 性能和重構

    本文將提供一些有用的提示和技巧來優化 Git 性能並重構代碼。Git 是一個非常流行的版本控制系統,但是在處理大型代碼倉庫時可能會有一些性能問題。如果你正在處理這樣的問題,本文將會…

    編程 2025-04-29
  • 優秀周記1000字的撰寫思路與技巧

    優秀周記是每個編程開發工程師記錄自己工作生活的最佳方式之一。本篇文章將從周記的重要性、撰寫思路、撰寫技巧以及周記的示例代碼等角度進行闡述。 一、周記的重要性 作為一名編程開發工程師…

    編程 2025-04-28
  • 使用@Transactional和分表優化數據交易系統的性能和可靠性

    本文將詳細介紹如何使用@Transactional和分表技術來優化數據交易系統的性能和可靠性。 一、@Transactional的作用 @Transactional是Spring框…

    編程 2025-04-28
  • Android ViewPager和ScrollView滑動衝突問題

    Android開發中,ViewPager和ScrollView是兩個常用的控制項。但是當它們同時使用時,可能會發生滑動衝突的問題。本文將從多個方面介紹解決Android ViewPa…

    編程 2025-04-28
  • Android如何點擊其他區域收起軟鍵盤

    在Android應用中,當輸入框獲取焦點彈出軟鍵盤後,我們希望能夠點擊其他區域使軟鍵盤消失,以提升用戶體驗。本篇文章將說明如何實現這一功能。 一、獲取焦點並顯示軟鍵盤 在Andro…

    編程 2025-04-28
  • Python性能優化方案

    本文將從多個方面介紹Python性能優化方案,並提供相應的示例代碼。 一、使用Cython擴展 Cython是一個Python編譯器,可以將Python代碼轉化為C代碼,可顯著提高…

    編程 2025-04-28
  • Python AUC:模型性能評估的重要指標

    Python AUC是一種用於評估建立機器學習模型性能的重要指標。通過計算ROC曲線下的面積,AUC可以很好地衡量模型對正負樣本的區分能力,從而指導模型的調參和選擇。 一、AUC的…

    編程 2025-04-28
  • Python性能分析: 如何快速提升Python應用程序性能

    Python是一個簡潔高效的編程語言。在大多數情況下,Python的簡潔和生產力為開發人員帶來了很大便利。然而,針對應用程序的性能問題一直是Python開發人員需要面對的一個難題。…

    編程 2025-04-27
  • 堆疊圖配色技巧分享

    堆疊圖是數據可視化中常用的一種表現形式,而配色則是影響堆疊圖觀感和傳達信息的重要因素之一。本文將分享一些堆疊圖配色的技巧,幫助你創造更好的數據可視化。 一、色彩搭配原則 色彩是我們…

    編程 2025-04-27

發表回復

登錄後才能評論