一、使用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