4

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;
}
fekra
  • 355
  • 1
  • 4
  • 17
  • Please be more specific on the nature of the error. For example, I see `position` in `onClick()`. Is it not the value that you expect it to be? – Al Lelopath Nov 22 '16 at 16:56
  • 1
    sorry my english not good i will try to explain i made GridView with Cards in RecyclerView when i use search like i search for name in RecyclerView i get this name but when i press on name it open another name not one that i searched it i hope you understand me – fekra Nov 22 '16 at 17:00
  • 3
    Your English is good enough. You need to be more specific about the error and where it is incorrect in the code. Is `position` the correct value? Is `name` the correct value? or `name1`? – Al Lelopath Nov 22 '16 at 17:22
  • error in position when i search only , when i'm in main before i search it give the right position but after i search about item it give wrong position – fekra Nov 22 '16 at 17:29

3 Answers3

6

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!

Community
  • 1
  • 1
abest
  • 587
  • 3
  • 14
0

You can do this by editing OnItemClickListener in Recycler adapter java.

Like this

 itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mListener!=null){
                    int position = getAdapterPosition();
                    String name = songListFiltered.get(position).getText1();
                    for (int i=0; i <songList.size(); i++){
                        if (name.equals(songList.get(i).getText1())){
                            position=i;
                            break;
                        }
                    }
                    if (position!=RecyclerView.NO_POSITION){
                        mListener.OnItemClick(position);
                    }

                }
            }
        });

For better understanding here's my full RecyclerAdapter.java

package com.jiunidengkw;

 import android.content.Context;
 import android.view.LayoutInflater;
  import android.view.View;
  import android.view.ViewGroup;
  import android.widget.Filter;
  import android.widget.Filterable;
  import android.widget.TextView;

  import androidx.annotation.NonNull;
  import androidx.recyclerview.widget.RecyclerView;

   import java.util.ArrayList;
   import java.util.List;

   public class RecyclerAdapter extends                           RecyclerView.Adapter<RecyclerAdapter.ExampleViewHolder> implements Filterable {

private List<Item> songList;
private  Context context;
private List<Item> songListFiltered;
private List<Item> songListFull;
private OnItemClickListener mListener;

public interface  OnItemClickListener{
    void OnItemClick(int position);
}
public void setOnItemClickListener(OnItemClickListener listener){
    mListener=listener;
}






public class ExampleViewHolder extends RecyclerView.ViewHolder {
    TextView textView1;
    TextView textView2;

    ExampleViewHolder(final View itemView) {
        super(itemView);
        textView1 =(TextView) itemView.findViewById(R.id.text_view1);
        textView2 =(TextView) itemView.findViewById(R.id.text_view2);

        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mListener!=null){
                    int position = getAdapterPosition();
                    String name = songListFiltered.get(position).getText1();
                    for (int i=0; i <songList.size(); i++){
                        if (name.equals(songList.get(i).getText1())){
                            position=i;
                            break;
                        }
                    }
                    if (position!=RecyclerView.NO_POSITION){
                        mListener.OnItemClick(position);
                    }

                }
            }
        });
    }
}

public  RecyclerAdapter(Context context, List<Item> songList) {
    this.context = context;
    this.songListFiltered = songList;
    this.songList = songList;
}

@NonNull
@Override
public ExampleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,
            parent, false);
    return new ExampleViewHolder(v);
}

@Override
public void onBindViewHolder(@NonNull ExampleViewHolder holder, int position) {

    holder.textView1.setText(songListFiltered.get(position).getText1());
    holder.textView2.setText(songListFiltered.get(position).getText2());
}

@Override
public int getItemCount() {

    return songListFiltered.size();
}

@Override
public Filter getFilter() {
    return exampleFilter;
}

private Filter exampleFilter = new Filter() {
    @Override
    protected FilterResults performFiltering(CharSequence charSequence) {
        String charString = charSequence.toString();

        if (charString.isEmpty()) {
            songListFiltered = songList;
        } else {
           ArrayList<Item> itemArrayList = new ArrayList<>();

            for (Item item : songList) {
                if (item.getText1().toLowerCase().contains(charString)||item.getText2().toLowerCase().contains(charString)) {
                    itemArrayList.add(item);

                }
            }
            songListFiltered =itemArrayList;
        }

        FilterResults item = new FilterResults();
        item.values = songListFiltered;

        return item;

    }

    @Override
    protected void publishResults(CharSequence charSequence, FilterResults item) {
       songListFiltered = (ArrayList<Item>) item.values;
        notifyDataSetChanged();
    }
};
   }

Thank You.

0

I've run in to the same problem with filtered results. The problem looks like this

actualList = [4, 6, 3, 8, 9, 5, 2]

filteredList = [4, 3, 5, 2] // lets say filtering with <= 5

So when clicking the item 3 for example, the position returning will be 1 instead of original position 2.

So a simple solution would be (if you're using arrayList or sort of)

// in onClick listener
val itemAtPosition = filteredList[position]
// actual item position can be obtained from actual list
val actualPosition = actualList.indexOf(itemAtPosition)

Hope someone finds it useful.

Monster Brain
  • 1,468
  • 16
  • 23