Each item on my RecyclerView has a button that has three states: OPEN, LOADING, and CLOSED.
Initially all the buttons are in the OPEN state. When a button is clicked, the state is changed to LOADING and a network call is performed in the background. After the network call succeeds, the button state should be changed to CLOSED.
So in my adapter I used the following:
holder.button.setOnClickListener(v -> {
holder.state = LOADING;
notifyItemChanged(holder.getAdapterPosition()); /* 1 */
callNetwork(..., () -> {
/* this is the callback that runs on the main thread */
holder.state = CLOSED;
notifyItemChanged(holder.getAdapterPosition()); /* 2 */
});
});
The LOADING state is always visualized correctly at /* 1 */
because getAdapterPosition()
gives me the correct position.
However, the CLOSED state of the button is never visualized, because getAdapterPosition
at /* 2 */
always returns -1
.
I might understand getAdapterPosition()
wrongly in this case.
How do I refresh the appearance of an item on a callback?
From the docs:
Note that if you've called
notifyDataSetChanged()
, until the next layout pass, the return value of this method will beNO_POSITION
NO_POSITION is a constant whose value is -1. This might explain why you are getting a return value of -1 here.
In any case, why don't you find the position of the model in the underlying dataset and then call notifyItemChanged(int position)
? You could save the model as a field in the holder.
For example:
public class MyHolder extends RecyclerView.ViewHolder {
private Model mMyModel;
public MyHolder(Model myModel) {
mMyModel = myModel;
}
public Model getMyModel() {
return mMyModel;
}
}
holder.button.setOnClickListener(v -> {
holder.state = LOADING;
notifyItemChanged(holder.getAdapterPosition());
callNetwork(..., () -> {
/* this is the callback that runs on the main thread */
holder.state = CLOSED;
int position = myList.indexOf(holder.getMyModel());
notifyItemChanged(position);
});
});
Alternatively you can just ignore if the position is -1, like this:
holder.button.setOnClickListener(v -> {
holder.state = LOADING;
int preNetworkCallPosition = holder.getAdapterPosition();
if (preNetworkCallPosition != RecyclerView.NO_POSITION) {
notifyItemChanged(preNetworkCallPosition);
}
callNetwork(..., () -> {
/* this is the callback that runs on the main thread */
holder.state = CLOSED;
int postNetworkCallPosition = holder.getAdapterPosition();
if (postNetworkCallPosition != RecyclerView.NO_POSITION) {
notifyItemChanged(postNetworkCallPosition);
}
});
});
getAdapterPosition(); It will always return -1 when recyclerview makes layout calculations. You are calling this methods inside ViewHolder.. It means RecyclerView is doing calculations.
If you need position inside click actions of view, call it in the public void onClick(final View v) method for example:
"@Override public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
final Students user = mUsers.get(position);
holder.Name.setText(user.getFullname());
holder.Index.setText(user.getIndex_number());
if (user.getThumbnail().equals("default")) {
holder.profile_image.setImageResource(R.drawable.profile_pic);
} else {
Picasso.get().load(user.getThumbnail())
.placeholder(R.drawable.profile_pic)
.into(holder.profile_image);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
**list_user_id = mUsers.get(position).getId();**
Intent Sub = new Intent(mContext, UserProfileActivity.class);
Sub.putExtra("user_id1", list_user_id);
mContext.startActivity(Sub);
getAdapterPosition(); It will always return -1 when recyclerview makes layout calculations. You are calling this methods inside ViewHolder.. It means RecyclerView is doing calculations.
If you need position inside click actions of view, call it in the public void onClick(final View v) method for example:
@Override public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
final Students user = mUsers.get(position);
holder.Name.setText(user.getFullname());
holder.Index.setText(user.getIndex_number());
**list_user_id = mUsers.get(position).getId();**
if (user.getThumbnail().equals("default")) {
holder.profile_image.setImageResource(R.drawable.profile_pic);
} else {
Picasso.get().load(user.getThumbnail())
.placeholder(R.drawable.profile_pic)
.into(holder.profile_image);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
Intent Sub = new Intent(mContext, UserProfileActivity.class);
Sub.putExtra("user_id1", list_user_id);
mContext.startActivity(Sub);
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