Viewholder's getAdapterPosition and getLayoutPosition is always -1

recyclerview viewholder example
viewholder lifecycle
oncreateviewholder example
viewholder listview
viewholder is abstract cannot be instantiated
recyclerview.viewholder kotlin
cannot resolve symbol viewholder
explain the role of a viewholder in a recyclerview

I have the following AssessmentAdapter class. In the constructor of my ViewHolder class, I findViewById() to get the ImageView with the delete icon, and assign the click event to it.

I am trying to find the position of my ViewHolder, and send this to the parameterized constructor of my OnDeleteIconClicked class, but the position is always -1. Why?

Here is my code:

public class AssessmentAdapter extends RecyclerView.Adapter<AssessmentAdapter.AssessmentViewHolder> {

private List<Assessment> assessmentList;
private IAssessmentsList context;

public AssessmentAdapter(List<Assessment> assessmentList, IAssessmentsList context){
    this.assessmentList = assessmentList;
    this.context = context;
}

@Override
public AssessmentViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View rowView = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.assessment_list_row, parent, false);

    rowView.setOnClickListener(new OnAdapterItemClicked());

    return new AssessmentViewHolder(rowView);
}

@Override
public void onBindViewHolder(AssessmentViewHolder holder, int position) {
    Assessment assessment = assessmentList.get(position);
    holder.txtClientName.setText(assessment.getClient());
    holder.txtAssessmentDate.setText(assessment.getInspectedDate());
    holder.imageView.setTag(assessment.getId());
}

@Override
public int getItemCount() {
    return assessmentList.size();
}

public class AssessmentViewHolder extends RecyclerView.ViewHolder{

    public TextView txtClientName, txtAssessmentDate;
    public ImageView imageView;

    public AssessmentViewHolder(View view){
        super(view);

        txtClientName = view.findViewById(R.id.txtClientName);
        txtAssessmentDate = view.findViewById(R.id.txtAssessmentDate);

        imageView= view.findViewById(R.id.deleteAssessment);
        int layoutPosition = getLayoutPosition(); //always -1
        int adapterPosition = getAdapterPosition(); //always -1
        imageView.setOnClickListener(new OnDeleteIconClicked(getAdapterPosition()));
    }
}

public class OnAdapterItemClicked implements View.OnClickListener{

    @Override
    public void onClick(View v) {
        context.OnAdapterItemClicked(v);
    }
}
public class OnDeleteIconClicked implements View.OnClickListener {

    private int position;

    public OnDeleteIconClicked(int position){
        this.position = position;
    }

    @Override
    public void onClick(View v) {
        context.OnDeleteItemClicked(Integer.parseInt(v.getTag().toString()), position);
    }

    public int getPosition() {
        return position;
    }
    public void setPosition(int position) {
        this.position = position;
    }
}
}

imageView.setOnClickListener(new OnDeleteIconClicked(getAdapterPosition()));

Take the line above and place it inside onBindViewHolder like so:

@Override
public void onBindViewHolder(AssessmentViewHolder holder, int position) {
    Assessment assessment = assessmentList.get(position);
    holder.txtClientName.setText(assessment.getClient());
    holder.txtAssessmentDate.setText(assessment.getInspectedDate());
    holder.imageView.setTag(assessment.getId());
    holder.imageView.setOnClickListener(new OnDeleteIconClicked(position));
}

Android Fundamentals: Working with the RecyclerView, Adapter , Understand how listview recycling works. How ListView's recycling mechanism works. You cannot recycle a row that is presently in use. The above link explains   ViewHolder design pattern is used to speed up rendering of your ListView - actually to make it work smoothly, findViewById is quite expensive (it does DOM parsing) when used each time a list item is rendered, it must traverse your layout hierarchy and also instantiate objects.


but the position is always -1. Why?

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,

inside ViewHolder { ....
...
view.setOnClickListener(new View.OnClickListener) {
        @Override
        public void onClick(View v) {
             int position = getAdapterPosition(); // This does not return -1, because calculation is done and views have been inflated.
        }
    }
);
....
}

What is the benefit of ViewHolder pattern in android?, Viewholder . Customizable Item Layouts - ListView can only layout items in a vertical linear arrangement and this cannot be customized. In contrast, the  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 View#findViewById (int) results. While LayoutParams belong to the LayoutManager, ViewHolders belong to the adapter.


Put your click event inside onBindViewHolder

holder.imageView.setOnClickListener(new OnDeleteIconClicked(position));

Using the RecyclerView, ViewHolder is a design pattern which can be applied when using a custom adapter. Every time when the adapter calls [code]getView()[/code] method, the  ViewHolder is a design pattern which can be applied when using a custom adapter. Every time when the adapter calls getView() method, the findViewById() method is also called. This is a very intensive work for the mobile CPU and so affects the performance of the application and the battery consumption increases. To avoid this, ViewHolder is used.


public class AssessmentViewHolder extends RecyclerView.ViewHolder {

public TextView txtClientName, txtAssessmentDate;
public ImageView imageView;

public AssessmentViewHolder(View view) {
 super(view);

 txtClientName = view.findViewById(R.id.txtClientName);
 txtAssessmentDate = view.findViewById(R.id.txtAssessmentDate);

 imageView = view.findViewById(R.id.deleteAssessment);
 int layoutPosition = getLayoutPosition(); //always -1
 int adapterPosition = getAdapterPosition(); //always -1

 // When intialise viewholder value of getAdapterPosition will be always -1
 // instead of passing value from constructor, get when onClick event occure
 imageView.setOnClickListener(new OnDeleteIconClicked()); 

} }
Change in OnDeleteIconClicked
public class OnDeleteIconClicked implements View.OnClickListener {

private int position;

@Override
public void onClick(View v) {
 this.position = getAdapterPosition();   
 context.OnDeleteItemClicked(Integer.parseInt(v.getTag().toString()), position);
}

public int getPosition() {
 return position;
}

}

Android Applications: What is ViewHolder in Android's Adapter class , The ViewHolder pattern is a pattern that a developer can use to increase the speed at which their ListView renders data. The reason for this  A ViewHolder is more than just a dumb object that only holds the item’s views. It is the very object that represents each item in our collection and will be used to display it. This powerful object is the reason I was driven to write this tutorial!


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);
BUT NOT

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

Optimizing Your ListView with the ViewHolder Pattern, The ViewHolder design pattern enables you to access each list item view without the need for the look up, saving valuable processor cycles. Recyclability is just a flag in ViewHolder, that you can manipulate by using setIsRecyclable () method of ViewHolder class. RecycleView makes use of it as well, making ViewHolders non-recyclable during animations. Manipulating a single flag from different independent places is usually a bad idea.


Android ViewHolder Pattern Example, We have just change RecyclerView adapter to make it compatible with multiple views. For that, here we will make multiple view holder for the  A ViewHolder. Inside your adapter, you will create a ViewHolder that contains the View information for displaying one item from the item's layout. The diagram below shows the relationship between the data, the adapter, the ViewHolder, and the layout manager. To implement these pieces, you will need to:


Android RecyclerView with multiple view type (multiple view holder), A ViewHolder describes an item view and metadata about its place within the RecyclerView. RecyclerView.Adapter implementations should subclass ViewHolder  Required ViewHolder in Adapters - ListView adapters do not require the use of the ViewHolder pattern to improve performance. In contrast, implementing an adapter for RecyclerView requires the use of the ViewHolder pattern for which it uses RecyclerView.Viewholder.


Adapter & ViewHolder, So we extend adapter to RecyclerView.Adapter<RecyclerView.ViewHolder>. So 3 overrided methods are there. onCreateViewHolder, onBindViewHolder and getItemCount in recyclerview adapter class.