RecyclerView<第五篇>:刷新机制
2020-02-11 本文已影响0人
NoBugException
RecyclerView的刷新分为以下两种情况:
- 刷新的数据量比较大或者刷新Item的位置不确定
- .刷新指定Item
1.如果大量的数据被修改或者被修改数据的位置不确定,则使用
adapter.notifyDataSetChanged();
这个方法很消耗性能,不到万不得已不要使用,请尽量使用下面的刷新方法。
2.刷新某一项(常用)
//刷新某Item中的所有组件
adapter.notifyItemChanged(position);
//刷新某Item中的部分组件
adapter.notifyItemChanged(position, payloads);
//插入Item
adapter.notifyItemInserted(position);
//删除Item
adapter.notifyItemRemoved(position);
//移动Item
adapter.notifyItemMoved(position, position + 1);
图片.png
需求1:点击按钮1,使图片和文字改变。
switch (view.getId()){
case R.id.image:
Toast.makeText(MainActivity.this, "点击了图片", Toast.LENGTH_SHORT).show();
break;
case R.id.button_1:
Toast.makeText(MainActivity.this, "点击了按钮1", Toast.LENGTH_SHORT).show();
PhotoBean photoBean = list.get(position);
photoBean.setName("修改!");
photoBean.setUrl("http://pic29.nipic.com/20130511/9252150_174018365301_2.jpg");
adapter.notifyItemChanged(position);
break;
case R.id.button_2:
Toast.makeText(MainActivity.this, "点击了按钮2", Toast.LENGTH_SHORT).show();
break;
}
10.gif
需求2:点击按钮2,使按钮2高亮。
首先添加一个clickButton状态
public class PhotoBean {
private String name;
private String url;
private byte clickButton;//0:点击了图片,1:点击了按钮1,2:点击了按钮2
public PhotoBean(){}
public PhotoBean(String url, String name, byte clickButton){
this.url = url;
this.name = name;
this.clickButton = clickButton;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public byte getClickButton() {
return clickButton;
}
public void setClickButton(byte clickButton) {
this.clickButton = clickButton;
}
}
修改onBindViewHolder方法,将按钮变黄
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
PhotoBean dataListBean = mData.get(position);
if(dataListBean != null){
Glide.with(mContext).load(dataListBean.getUrl()).into(((ViewHolder)holder).imgView);
((ViewHolder)holder).tvName.setText(dataListBean.getName());
if(dataListBean.getClickButton() == 2){
((ViewHolder)holder).button_2.setBackgroundColor(Color.YELLOW);
}
}
((ViewHolder)holder).imgView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mOnItemClickLitener != null) {
if(mData != null && mData.size() > 0){
mOnItemClickLitener.onItemClick(((ViewHolder)holder).imgView, position);
}
}
}
});
((ViewHolder)holder).button_1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mOnItemClickLitener != null) {
if(mData != null && mData.size() > 0){
mOnItemClickLitener.onItemClick(((ViewHolder)holder).button_1, position);
}
}
}
});
((ViewHolder)holder).button_2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mOnItemClickLitener != null) {
if(mData != null && mData.size() > 0){
mOnItemClickLitener.onItemClick(((ViewHolder)holder).button_2, position);
}
}
}
});
}
效果如下:
11.gif
这样貌似已经实现了功能,但是存在两个严重的弊端:
1.我只要将按钮2改变颜色就行了,为什么图片还会刷新?
2.我每次点击按钮2,图片、文字、按钮都要重新排版一次,严重消耗性能,也许现在手机性能比较好,很多人不在乎,但是我在乎。
解决方案:使用payloads实现刷新Item中的部分控件。
修改按钮2点击事件实现
case R.id.button_2:
Toast.makeText(MainActivity.this, "点击了按钮2", Toast.LENGTH_SHORT).show();
PhotoBean photoBean2 = new PhotoBean();
photoBean2.setClickButton((byte) 2);
adapter.notifyItemChanged(position, photoBean2);
break;
添加回调方法
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List<Object> payloads) {
if(payloads != null && !payloads.isEmpty()){
if(payloads.get(0) instanceof PhotoBean){
PhotoBean photoBean = (PhotoBean) payloads.get(0);
if(photoBean.getClickButton() == 2){
((ViewHolder)holder).button_2.setBackgroundColor(Color.YELLOW);
}
}
}else{
onBindViewHolder(holder, position);
}
}
展示效果
12.gif需求3:实现添加删除和移动功能
case R.id.button_3:
Toast.makeText(MainActivity.this, "添加Item", Toast.LENGTH_SHORT).show();
list.add(position, new PhotoBean(list.get(position).getUrl(), list.get(position).getName(), list.get(position).getClickButton()));
adapter.notifyItemInserted(position);
break;
case R.id.button_4:
Toast.makeText(MainActivity.this, "删除Item", Toast.LENGTH_SHORT).show();
list.remove(position);
adapter.notifyItemRemoved(position);
break;
case R.id.button_5:
Toast.makeText(MainActivity.this, "移动Item", Toast.LENGTH_SHORT).show();
Collections.swap(list,position,position+1);// 元素互换
adapter.notifyItemMoved(position, position + 1);
break;
添加效果:
13.gif
删除效果:
14.gif
移动效果:
15.gif
另外,以上讲解的都是刷新一个Item, 下面四个方法是更新多个Item
public final void notifyItemRangeChanged(int positionStart, int itemCount);
public final void notifyItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload);
public final void notifyItemRangeInserted(int positionStart, int itemCount);
public final void notifyItemRangeRemoved(int positionStart, int itemCount) ;
其实,更新一个Item的方法,底层都会调用以上四个方法的其中一个,只是此时itemCount=1。
需要注意的是:
mRecyclerView.setHasFixedSize(false);
您可能还需要知道setHasFixedSize的的使用。
- 当setHasFixedSize为true时,Item高度变化时,不会重新计算高度;
- 当setHasFixedSize为false时,Item高度变化时,会重新计算高度;
setHasFixedSize默认是false。
当执行
onItemRangeChanged()
onItemRangeInserted()
onItemRangeRemoved()
onItemRangeMoved()
时,可以设置setHasFixedSize为true,让Item的高度不会重新计算,这样可以保证性能。
如果调用了notifyDataSetChanged,Item的大小总是会被重新计算。
大家可以参考一下文章:
RecyclerView性能优化:setHasFixedSize
[本章完...]