onBindViewHolder() is never called on view at position even though RecyclerView.findViewHolderForAdapterPosition() returns null at that position onBindViewHolder() is never called on view at position even though RecyclerView.findViewHolderForAdapterPosition() returns null at that position android android

onBindViewHolder() is never called on view at position even though RecyclerView.findViewHolderForAdapterPosition() returns null at that position


This is happening because:

  • The views are not added to the recyclerview (getChildAt will not work and will return null for that position)
  • They are cached also (onBind will not be called)

Calling recyclerView.setItemViewCacheSize(0) will fix this "problem".

Because the default value is 2 (private static final int DEFAULT_CACHE_SIZE = 2; in RecyclerView.Recycler), you'll always get 2 views that will not call onBind but that aren't added to the recycler


In your case views for positions 8 and 9 are not being recycled, they are being detached from the window and will be attached again. And for these detached view onBindViewHolder is not called, only onViewAttachedToWindow is called. If you override these function in your adapter, you can see what I am talking.

@Override    public void onViewRecycled(ViewHolder vh){        Log.wtf(TAG,"onViewRecycled "+vh);    }    @Override    public void onViewDetachedFromWindow(ViewHolder viewHolder){        Log.wtf(TAG,"onViewDetachedFromWindow "+viewHolder);    }

Now in order to solve your problem you need to keep track of the views which were supposed to recycled but get detached and then do your section process on

@Override    public void onViewAttachedToWindow(ViewHolder viewHolder){        Log.wtf(TAG,"onViewAttachedToWindow "+viewHolder);    }


The answers by Pedro Oliveira and Zartha are great for understanding the problem, but I don't see any solutions I'm happy with.

I believe you have 2 good options depending on what you're doing:

Option 1

If you want onBindViewHolder() to get called for an off-screen view regardless if it's cached/detached or not, then you can do:

RecyclerView.ViewHolder view_holder = recycler_view.findViewHolderForAdapterPosition( some_position );if ( view_holder != null ){    //manipulate the attached view}else //view is either non-existant or detached waiting to be reattached    notifyItemChanged( some_position );

The idea is that if the view is cached/detached, then notifyItemChanged() will tell the adapter that view is invalid, which will result in onBindViewHolder() getting called.

Option 2

If you only want to execute a partial change (and not everything inside onBindViewHolder()), then inside of onBindViewHolder( ViewHolder view_holder, int position ), you need to store the position in the view_holder, and execute the change you want in onViewAttachedToWindow( ViewHolder view_holder ).

I recommend option 1 for simplicity unless your onBindViewHolder() is doing something intensive like messing with Bitmaps.