【问题标题】:notifyItemChanged call onCreateViewHoldernotifyItemChanged 调用 onCreateViewHolder
【发布时间】:2020-10-28 12:08:27
【问题描述】:

我的 recyclerView 适配器有一个奇怪的问题,我只想根据选择显示/隐藏 ImageView,但是当我在点击侦听器中调用 notifyItemChanged(selection) 时,它会调用 onCreateViewHolder 并延迟刷新de view,我不知道为什么,也没有找到其他解决方案来执行我需要的操作。

这是我的适配器:

public class ChannelAdapter extends RecyclerView.Adapter<ChannelAdapter.ChannelHolder> {
    private ArrayList<Integer> channelList;
    private Integer selection = 0;

    public ChannelAdapter(ArrayList<Integer> channelList) {
        this.channelList = channelList;
    }

    @NotNull
    @Override
    public ChannelHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Log.d(TAG, "onCreateViewHolder: ");
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_channel_item_selected, parent, false);
        ChannelHolder holder = new ChannelHolder(view);
        return holder;
    }

    @SuppressLint("SetTextI18n")
    @Override
    public void onBindViewHolder(ChannelHolder holder, int position) {
        Log.d(TAG, "onBindViewHolder: "+position);
        holder.textViewChannelId.setText("#"+channelList.get(position));
        holder.textViewChannel.setText(channelList.get(position).toString());

        if(position==selection){
            holder.imageViewSelectorLeft.setVisibility(View.VISIBLE);
            holder.imageViewSelectorRight.setVisibility(View.VISIBLE);
        }
        else{
            holder.imageViewSelectorLeft.setVisibility(View.INVISIBLE);
            holder.imageViewSelectorRight.setVisibility(View.INVISIBLE);
        }
    }

    @Override
    public int getItemCount() {
        return channelList.size();
    }

    public class ChannelHolder extends RecyclerView.ViewHolder {
        TextView textViewChannel, textViewChannelId;
        ImageView imageViewSelectorLeft, imageViewSelectorRight;

        public ChannelHolder(View itemView) {
            super(itemView);
            textViewChannelId = itemView.findViewById(R.id.textViewChannelId);
            textViewChannel = itemView.findViewById(R.id.textViewChannel);
            imageViewSelectorLeft = itemView.findViewById(R.id.imageViewSelectorLeft);
            imageViewSelectorRight = itemView.findViewById(R.id.imageViewSelectorRight);

            itemView.setOnClickListener(v -> {
                notifyItemChanged(selection);
                selection=getAdapterPosition();
                notifyItemChanged(selection);
            });
        }
    }
}

我错过了什么还是我做错了? 在此先感谢您的帮助

编辑: 我尝试使用 notifyItemChanged 并将有效负载设置为 1 并覆盖 onBindViewHolder 以获取有效负载,但它仍然调用 onCreateViewHolder,即使 mSupportsChangeAnimations 设置为 false

【问题讨论】:

  • 使用notifyItemChanged(position, payload) 并覆盖onBindViewHolder(holder, position, payloads)
  • 已经尝试将有效负载设置为 1 并覆盖方法,但它仍然调用 onCreateViewHolder

标签: android android-recyclerview adapter sectionedrecyclerviewadapter


【解决方案1】:

默认情况下,您的 RecyclerView 将附加一个DefaultItemAnimator。当您在适配器上调用notifyItemChanged() 时,系统最终会调用DefaultItemAnimator 以确定是否需要创建一个新的ViewHolder 或者是否可以“重用”现有的ViewHolder

@Override
public boolean canReuseUpdatedViewHolder(@NonNull ViewHolder viewHolder,
        @NonNull List<Object> payloads) {
    return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
}

超类实现:

@Override
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) {
    return !mSupportsChangeAnimations || viewHolder.isInvalid();
}

这些建议有两种简单的方法可以确保 ViewHolder 被重复使用而不是重新创建:

  • 确保payloads 列表不为空。这是通过调用adapter.notifyItemChanged(position, payload) 来完成的。 payload 是什么无关紧要,只要它不为空即可。
  • mSupportsChangeAnimations 设置为false 为您的DefaultItemAnimator
DefaultItemAnimator animator = (DefaultItemAnimator) recyclerView.getItemAnimator();
animator.setSupportsChangeAnimations(false);

【讨论】:

  • 感谢您的解释,我在我的回收器中将setSupportsChangeAnimation 设置为false,并在调用notifyItemChanged 时将有效负载设置为1,但当我选择一个项目时它仍然调用onCreateViewHolder...我'已尝试使用有效负载 args 覆盖 onBindViewHolder 方法,但它不会改变任何东西......
  • 非常感谢!!!这行得通!!! recyclerview 的细微差别真的很难理解。为理解为什么在 notifyItemChanged() 上调用 onCreateViewHolder 付出了很多努力。很好的解释!!!
【解决方案2】:

你可以这样调用你的适配器

YourAdapter adapter = new YourAdapter(yourList, yourActivity.this);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();

然后您可以将此代码放在适配器中的 itemClick 上

if(position==getAdapterPosition()){
        holder.imageViewSelectorLeft.setVisibility(View.VISIBLE);
        holder.imageViewSelectorRight.setVisibility(View.VISIBLE);
    }
    else{
        holder.imageViewSelectorLeft.setVisibility(View.INVISIBLE);
        holder.imageViewSelectorRight.setVisibility(View.INVISIBLE);
    }

【讨论】:

  • 我不明白你所说的对我有什么帮助,我在适配器构造函数中与yourActivity.this 有什么关系?那么onItemClick 呢?不清楚……
  • yourActivity.this 是传递给适配器的上下文(如果您正在传递)。如果您没有将上下文传递给适配器,请跳过此步骤。 yourActivity.this 是传递给适配器的上下文,在项目上单击粘贴上面的代码希望能正常工作
  • 我知道,但是当我使用 onItemChange 时,我不明白它应该如何帮助我避免调用 onCreateViewHolder
猜你喜欢
  • 2023-03-17
  • 1970-01-01
  • 2020-06-24
  • 1970-01-01
  • 1970-01-01
  • 2021-08-07
  • 2019-09-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多