ard题

RecyclerView<第五篇>:刷新机制

2020-02-11  本文已影响0人  NoBugException

RecyclerView的刷新分为以下两种情况:

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默认是false。
当执行

onItemRangeChanged()
onItemRangeInserted()
onItemRangeRemoved()
onItemRangeMoved()

时,可以设置setHasFixedSize为true,让Item的高度不会重新计算,这样可以保证性能。

如果调用了notifyDataSetChanged,Item的大小总是会被重新计算。

大家可以参考一下文章:

RecyclerView性能优化:setHasFixedSize

[本章完...]

上一篇下一篇

猜你喜欢

热点阅读