Lint错误 "不要将位置视为固定; 仅在需要时使用..."

36

我正在为开源库做贡献,但是在这段代码中出现了一个lint错误:"Do not treat position as fixed; only use immediately and call holder.getAdapterPosition() to look it up later"

  @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    mAdapter.onBindViewHolder(holder, position);

    if (!isFirstOnly || position > mLastPosition) {
      for (Animator anim : getAnimators(holder.itemView)) {
        anim.setDuration(mDuration).start();
        anim.setInterpolator(mInterpolator);
      }
      mLastPosition = position;
    } else {
      ViewHelper.clear(holder.itemView);
    }
  }

我已经检查过了,这是因为该位置被保存供将来使用。这是向库的创建者提出的一个问题,为什么他们需要这种逻辑。但当我将该位置的使用方式更改为使用 holder.getAdapterPosition() 时,问题消失了:

  @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    mAdapter.onBindViewHolder(holder, position);

    if (!isFirstOnly || holder.getAdapterPosition() > mLastPosition) {
      for (Animator anim : getAnimators(holder.itemView)) {
        anim.setDuration(mDuration).start();
        anim.setInterpolator(mInterpolator);
      }
      mLastPosition = holder.getAdapterPosition();
    } else {
      ViewHelper.clear(holder.itemView);
    }
  }

我认为从概念上讲并没有太大变化,但现在Lint已经满意了。为什么呢?


1
不能保证绑定操作的调用顺序与实际可见项视图的顺序完全一致。因此,mLastPosition 可能不是最后一个可见项。 - S.D.
1
好的,这对于库的创建者来说是个不错的输入,但是为什么现在 lint 满意了呢? - Eugen Martynov
2个回答

39

更新: 现在方法getAdapterPosition()已经过时了。


RecyclerView.Adapter.onBindViewHolder() 的文档说明如下:

请注意,与 ListView 不同,如果数据集中的项目位置发生更改,除非该项本身无效或无法确定新位置,否则 RecyclerView 将不会再次调用此方法。因此,在此方法内部获取相关数据项时,应仅使用 position 参数,而不应保留其副本。如果您需要稍后使用项目的位置(例如在单击侦听器中),请使用 getAdapterPosition(),它将具有更新的适配器位置。

从技术上讲,项目可能会被重新排列(如排序或移动),并且不需要绑定,因为项目尚未失效。这意味着如果项目显示相同的数据,但是它们在列表中的位置/索引发生变化,则可能不会调用onBindViewHolder()。接收到的position变量仅在绑定函数的范围内有效,并且不总是指向数据集中的正确位置。这就是为什么每次需要更新位置时都必须调用getAdapterPosition()函数。

在我看来,mLastPosition = holder.getAdapterPosition();仍然有潜在错误。因为项目可能会被重新排列,而mLastPosition仍然指向旧位置。

关于为什么Lint保持沉默,也许是因为Lint的规则不够严格。它只检查是否复制了position参数。


1
实际上,它在 Linux 构建时失败了,但在 Mac 上通过了。 - Eugen Martynov
23
为什么谷歌发布会导致此Lint错误的代码示例? - IgorGanapolsky
@taurelas Lint 工具基于规则分析代码文件。规则是可以访问源构造并查找错误模式的程序。这里有一个例子 - S.D.
@S.D. 好的,这是一个自定义规则来配合该库使用。谢谢。 - Maciej Beimcik
1
'getAdapterPosition()'已被弃用,请使用'getBindingAdapterPosition'代替。 - Ali Akram
显示剩余3条评论

2

我的旧代码:

@Override

//here int position gave a error

public void onBindViewHolder(@NonNull CartListAdapator.ViewHolder holder, int position) {

    holder.titleTxt.setText(foodDomains.get(position).getTitle());
    holder.feeEachItem.setText(String.valueOf(foodDomains.get(position).getFee()));

    
    holder.plusItem.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            managementCart.plusNumberFood(foodDomains, position, new ChangeNumberItemListener() {
                @Override
                public void changed() {
                    notifyDataSetChanged();
                    changeNumberItemListener.changed();
                }
            });
        }
    });

所以,在 plusNumberFood() 方法中,我更改了参数的位置 -> holder.getAdapterPosition();

我的新代码:

@Override
public void onBindViewHolder(@NonNull CartListAdapator.ViewHolder holder, int position) {
    holder.titleTxt.setText(foodDomains.get(position).getTitle());
    holder.feeEachItem.setText(String.valueOf(foodDomains.get(position).getFee()));

    holder.plusItem.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            managementCart.plusNumberFood(foodDomains, holder.getAdapterPosition(), new ChangeNumberItemListener() {
                @Override
                public void changed() {
                    notifyDataSetChanged();
                    changeNumberItemListener.changed();
                }
            });
        }
    });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接