Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.7k views
in Technique[技术] by (71.8m points)

android - Lint error "Do not treat position as fixed; only use immediately..."

I'm contributing to open source library and got lint error "Do not treat position as fixed; only use immediately and call holder.getAdapterPosition() to look it up later" for this code:

  @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);
    }
  }

I've checked that it is because the position is saved for the future use. It is a question to library creator why they need this logic. But issue disappeared when I change the usage of the position to the usage 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);
    }
  }

I assume that conceptually it didn't change much but lint is satisfied now. Why?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The documentation of RecyclerView.Adapter.onBindViewHolder() states:

Note that unlike ListView, RecyclerView will not call this method again if the position of the item changes in the data set unless the item itself is invalidated or the new position cannot be determined. For this reason, you should only use the position parameter while acquiring the related data item inside this method and should not keep a copy of it. If you need the position of an item later on (e.g. in a click listener), use getAdapterPosition() which will have the updated adapter position

So, technically items may be re-arranged (like sorted, or moved around) and binding will not be necessary because items are not invalidated yet. This means onBindViewHolder() may NOT be called if items show the same data, but just their position/index in a list changes. The position variable received holds true only for the scope of bind function and will not always point to the correct position in the data set. That's why the function getAdapterPosition() must be called every time updated position is needed.

IMHO, mLastPosition = holder.getAdapterPosition(); is still potentially wrong. Because item may be re-arranged and mLastPosition still points to old position.

About why lint is silent, perhaps Lint's rule is not that thorough. It's only checking whether the position parameter is being copied or not.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...