fekra fekra - 12 days ago 6
Android Question

RecyclerView search filter getting wrong position

i use RecyclerView and i made filter on it and i have problem

after i search when i press on item i get wrong position not one i searched it please help me to solve this problem

RecyclerView Adapter



public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {

Context context;
List<listitem_gib> getDataAdapter;



public RecyclerViewAdapter(List<listitem_gib> getDataAdapter, Context context){

super();

this.getDataAdapter = getDataAdapter;
this.context = context;

}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview_layout, parent, false);

ViewHolder viewHolder = new ViewHolder(v,context,getDataAdapter);

return viewHolder;
}

@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {

listitem_gib getDataAdapter1 = getDataAdapter.get(position);

holder.name.setText(getDataAdapter1.getName());
holder.num.setText(getDataAdapter1.getnum());
Picasso.with(context).load("http://i-geeky.info/android/image/" + getDataAdapter1.getimg()).into(holder.img1);


}

@Override
public int getItemCount() {

return getDataAdapter.size();
}

class ViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener{

public TextView name;
public TextView num;
public ImageView img1;

ImageButton fav;

Context context;
List<listitem_gib> getDataAdapter;


public ViewHolder(View itemView, Context context ,List<listitem_gib> getDataAdapter ) {

super(itemView);
itemView.setOnClickListener(this);
this.getDataAdapter = getDataAdapter;
this.context = context;
this.fav= (ImageButton) itemView.findViewById(R.id.btn_fav);

name = (TextView) itemView.findViewById(R.id.Main_Text) ;
num = (TextView) itemView.findViewById(R.id.Second_Text) ;
img1 = (ImageView) itemView.findViewById(R.id.img1) ;

}


@Override
public void onClick(View v) {

int position = getAdapterPosition();
listitem_gib getDataAdapter =this.getDataAdapter.get(position);
Intent intent = new Intent(this.context,Rewaya_info.class);
intent.putExtra("name",getDataAdapter.getName());
intent.putExtra("url",getDataAdapter.geturl());
intent.putExtra("img",getDataAdapter.getimg());
intent.putExtra("num",getDataAdapter.getnum());
intent.putExtra("size",getDataAdapter.getsize());
this.context.startActivity(intent);

}
}
public void setFilter(List<listitem_gib> newList)
{
getDataAdapter = new ArrayList<>();
getDataAdapter.addAll(newList );
notifyDataSetChanged();
}}


Activity



@Override
public boolean onQueryTextChange(String newText) {

newText = newText.toLowerCase();
List<listitem_gib> newList = new ArrayList<>();
for (listitem_gib list : GetDataAdapter1){
String name = list.getName().toLowerCase();
String name1 = list.getnum().toLowerCase();

if (name.contains(newText) || name1.contains(newText)){
newList.add(list);
}
}
recyclerViewadapter.setFilter(newList);
return true;
}

Answer

The recyclerview re-uses existing elements and simply binds new data to these elements--this prevents items needing to be created & destroyed, instead they are recycled ;).

Take a look at the constructor of your ViewHolder. In it you pass in the initial list of data your ViewHolders are binding to. In effect, this creates a static binding to your initial list, not the filtered list:

public ViewHolder(View itemView, Context context ,List<listitem_gib> getDataAdapter ) {
    super(itemView);
    itemView.setOnClickListener(this);
    this.getDataAdapter = getDataAdapter; <-- this is stored in the viewholder
    ...
}

What may work better is to make better use of the onBindViewHolder of the RecyclerViewAdapter. This will allow the ViewHolder to use the current items in the adapter at the time of the click as follows:

@Override 
public void onBindViewHolder(final ViewHolder holder, final int position) {

    listitem_gib item =  getDataAdapter.get(position);
    holder.bind(item);
}

Update your ViewHolder as follows:

class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

    private TextView name;
    private TextView num;
    private ImageView img1;

    ImageButton fav;

    Context context;
    private listitem_gib currentItem; //<-- allows this viewholder to keep a reference to the bound item

    public ViewHolder(View itemView, Context context) {  //<-- no more adapter in constructor
        super(itemView);
        itemView.setOnClickListener(this);
        this.context = context;
        this.fav = (ImageButton) itemView.findViewById(R.id.btn_fav);
        name = (TextView) itemView.findViewById(R.id.Main_Text) ;
        num = (TextView) itemView.findViewById(R.id.Second_Text) ;
        img1 = (ImageView) itemView.findViewById(R.id.img1) ;
    }

    void bind (listitem_gib item) {  //<--bind method allows the ViewHolder to bind to the data it is displaying
        name.setText(item.getName());
        num.setText(item.getnum());
        Picasso.with(this.context).load("http://i-geeky.info/android/image/" + item.getimg()).into(holder.img1);
        currentItem = item; //<-- keep a reference to the current item
    }

    @Override
    public void onClick(View v) {
        Intent intent = new Intent(this.context,Rewaya_info.class);
        intent.putExtra("name",currentItem.getName());  // <-- makes use of currentItem instead of adapter
        intent.putExtra("url",currentItem.geturl());
        intent.putExtra("img",currentItem.getimg());
        intent.putExtra("num",currentItem.getnum());
        intent.putExtra("size",currentItem.getsize());
        this.context.startActivity(intent);
    }
}

Good luck!

Comments