一、使用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-hk/n/259389.html
微信掃一掃
支付寶掃一掃