Asked  4 Months ago    Answers:  5   Viewed   345 times

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?

 Answers

71

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.

Saturday, July 3, 2021
 
MGP
answered 4 Months ago
MGP
73

For handling item clicks in a RecyclerView, I recommend you move your logic into the ViewHolder of your Adapter. You can have your ViewHolder implement View.OnClickListener, and override the onClick() method to preform an action. If your action depends on the item clicked, you can reference it using getAdapterPosition(). The code will look something like this:

public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
   public MyViewHolder(View view) {
      super(view);

      view.setOnClickListener(this);
   }

   @Override
   public void onClick(View view) {
      // Get the item clicked
      // For this example, I'm assuming your data source is of type `List<MyObject>`
      MyObject myObject = mDataSource.get(getAdapterPosition());
      // Then you can do any actions on it, for example: 
      myObject.setChecked();
   }
}

Clearly the logic that happens inside onClick will change to your example, but I hope this sets you on the right track. For another sample of this, as well as a bit of an explanation for the benefits of handling click logic inside the ViewHolder, check out a blog post that I wrote comparing RecyclerView and ListView (look for the section labeled "More explicit click listeners").

Wednesday, July 28, 2021
 
Fredy
answered 3 Months ago
41

You can define your own function to act as you want

plus <- function(x) {
 if(all(is.na(x))){
   c(x[0],NA)} else {
   sum(x,na.rm = TRUE)}
 }


rbind(dt1, dt2)[,lapply(.SD, plus), by = Name]
Tuesday, August 10, 2021
 
nirvair
answered 2 Months ago
75

RecyclerView implements NestedScrollingChild2 inteface but does not implement any of NestedScrollingParent* interfaces, so it can be a scrollable child, but cannot be a parent for such a child. To make it work you need to create a subclass of RecyclerView and implement NestedScrollingParent interface yourself. There are some articles also on how to do that, for instance this one.

Saturday, August 21, 2021
 
ielyamani
answered 2 Months ago
61

The port 8888 is used almost exclusively by Jupyter, and the fact that it's in use indicates more than anything that you have another Jupyter session already running. I'm 99% certain you can just kill the task that's using it, or you can run

jupyter notebook list

to see current notebooks. And as mentioned in the other answer you can run

jupyter notebook --port 8889

To run on a different port instead (replace 8889 by any other number you'd like).

Wednesday, September 29, 2021
 
user35358
answered 3 Weeks ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :