[first time asker and first time android coder so I apologize if I do something wrong]
I'm trying to change the value inside of an itemview on my recycler. However, if that itemview happens to be offscreen, the findViewBy[layout,adapter,or id] comes up null.
public void setUserActive(UserListAdapter adapter, RecyclerView recyclerView, int position, View v) {recyclerView.findViewHolderForItemId(adapter.getItemId(position));
TextView txtActive = (TextView) vh.itemView.findViewById(R.id.user_isActive);
txtActive.setText("Active");
UserListAdapter.ViewHolder inactivevh = (UserListAdapter.ViewHolder) recyclerView.findViewHolderForItemId(adapter.getItemId(adapter.getActiveUserPosition()));
TextView txtInActive = (TextView) inactivevh.itemView.findViewById(R.id.user_isActive);
txtInActive.setText("");
adapter.setActiveUserPosition(position);
}
I've tried a few different ways, from using
UserListAdapter.ViewHolder vh = (UserListAdapter.ViewHolder) recyclerView.findViewHolderForLayoutPosition(position);
or
UserListAdapter.ViewHolder inactivevh = (UserListAdapter.ViewHolder) recyclerView.findViewHolderForAdapterPosition(position)
and they all fail when the view that should be inactivevh is off screen.
I've set the adapter to hasStableIDs = true notifydatasetchanged doesn't seem to help either.
viewholder does not maintain its state when scrolled off screen.
A ViewHolder describes an item view and metadata about its place within the RecyclerView. Adapter implementations should subclass ViewHolder and add fields for caching potentially expensive findViewById results.
But there IS an easy way to get the ViewHolder from a specific position (something you'll probably do a lot in the Adapter). myRecyclerView. findViewHolderForAdapterPosition(pos); NOTE: If the View has been recycled, this will return null .
You can use the ViewHolder's getAdapterPosition() to retrieve the item's position within an interface method. Then store the clicked position in a member variable.
If an item is on screen (laid out) you can get its view holder conveniently using methods you described. If an item is not on screen it will get updated as soon as it gets scrolled in via onBindViewHolder
. If it doesn't get scrolled in, it's not presented to user ergo any attempt to update it is a waste of processing power (apart from being impossible because the item doesn't have a view holder assigned).
Meaning: Implement your adapter in such way that onBindViewHolder
is able to pull up-to-date data. Looks like you're all set up and can use this:
public void setUserActive(UserListAdapter adapter, RecyclerView recyclerView, int position) {
// Retrieve the old active user ID so we can mark him deactivated.
final int oldUserActivePosition = adapter.getActiveUserPosition();
// Setup the adapter with current data.
adapter.setActiveUserPosition(position);
// Do NOT use stable IDs and this method. It just doesn't work as expected.
// recyclerView.findViewHolderForItemId(adapter.getItemId(position));
// Activate new user.
UserListAdapter.ViewHolder holder = (UserListAdapter.ViewHolder) recyclerView.findViewHolderForAdapterPosition(position);
if (holder == null) {
// The item is off screen, no need to update it yet.
} else {
// Update the on screen item. The logic is already implemented in the adapter.
adapter.onBindViewHolder(holder, position);
}
// Deactivate previous user.
holder = (UserListAdapter.ViewHolder) recyclerView.findViewHolderForAdapterPosition(oldUserActivePosition);
if (holder != null) {
adapter.onBindViewHolder(holder, oldUserActivePosition);
}
}
Simplify the if-else block in your code of course.
I just realized how unnecessarily complicated the original solution is. As long as the adapter can react to all events you need in onBindViewHolder
and the binding is realtively easy this will suffice:
public void setActiveUserPosition(int position) {
if (mActiveUserPosition != position) {
int oldPosition = mActiveUserPosition;
mActiveUserPosition = position;
notifyItemChanged(oldPosition);
notifyItemChanged(position);
}
}
All you need to call now is adapter.setActiveUserPosition(position);
which renders setUserActive
method obsolete.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With