Search code examples
androidandroid-recyclerviewonclicklistener

RecyclerView: wrong position in filtered List


I have a RecyclerView list of CardView items. I then use a simple filter method with a SearchView widget to filter the list. When I then click on a filtered CardView to launch a CardViewDetails Activity, the UI is showing the CardView from the original List and not the filtered List. For example, I have a list of twenty items in the original List. When I enter a search constraint the filtered List correctly shows three CardViews in the RecyclerView. When I click on the third CardView in the List, the UI returns the third CardView from the original List and not the third CardView from the filtered List. What am I missing here?

Adapter:

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

private List<ListItem> mListItems, filteredList;
Context mContext;
private RecyclerItemClickListener recyclerItemClickListener;
private RecyclerView mRecyclerView;
/**********************************************************/
private String searchString = "";
/**********************************************************/

public MyRecylerAdapter(Context context, List<ListItem> listItems) {
    this.mContext = context;
    this.mListItems = listItems;
    this.filteredList = new ArrayList<>();
    this.filteredList.addAll(this.mListItems);
}

// RecyclerItemClickListener is the public interface file used to reach the MainActivity
public void setOnItemClickListener(RecyclerItemClickListener recyclerItemClickListener) {
    this.recyclerItemClickListener = recyclerItemClickListener;
}

// Get the Item's position.
public ListItem getItem(int position) {
    return filteredList.get(position);
}

@Override
public int getItemCount() {
    if (filteredList.size() >0) {
        return filteredList.size();
    }
    else {
        return mListItems.size();
    }
}

public void setFilter(List<ListItem> listItems, String searchString) {
    // Note: the String is to get s.toString() from the Main Activity SearchView.
    filteredList = new ArrayList<>();
    filteredList.addAll(listItems);
    this.searchString = searchString;
    notifyDataSetChanged();
}

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

    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_contact_item, parent, false);
    final ItemHolder itemHolder = new ItemHolder(view);

        // Attach a Click listener to the items's (row) view.
        // itemView is from the ItemHolder() below.
        // onItemClick is the click method in MainActivity.
        itemHolder.itemView.setOnClickListener(new View.OnClickListener() {                
            @Override
            public void onClick(View view) {

                int adapterPos = itemHolder.getAdapterPosition(); // get the item position.                    
                if (adapterPos != RecyclerView.NO_POSITION) {
                    if (recyclerItemClickListener != null) {
                        // pass the item to the Main Activity
                        // through the RecyclerItemClickListener file and its
                        // public interface.
                        recyclerItemClickListener.onItemClick(itemHolder.itemView,adapterPos);
                    }
                }
            }
        });            
    return itemHolder;
}

private static class ItemHolder extends RecyclerView.ViewHolder {

    private TextView cardBlankText2; 

    private ItemHolder(View itemView) {
        super(itemView);

        cardBlankText2 = (TextView) itemView.findViewById(R.id.cardBlankText2);            
}

public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {

    final ListItem listItem = filteredList.get(position);
    final ItemHolder itemHolder = (ItemHolder) holder;

    itemHolder.cardBlankText2.setText(listItem.getTodo());
}

Activity:

public class MainActivity extends AppCompatActivity implements
    RecyclerItemClickListener {

private List<ListItem> allList = new ArrayList<>();
private RecyclerView mRecyclerView;
private SQLiteDB sqLiteDB;
private MyRecylerAdapter adapter;    
private CardView cardview;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    sqLiteDB = SQLiteDB.getInstance(this);        
    mRecyclerView = (RecyclerView)findViewById(R.id.list_recyclerview);        
    final LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);        
    mRecyclerView.setLayoutManager(layoutManager);
    allList = sqLiteDB.getAllDBItems();

    adapter = new MyRecylerAdapter(this, allList);
    adapter.setOnItemClickListener(this);
    mRecyclerView.setAdapter(adapter);
}

@Override
public void onItemClick(View view, int position) {
    cardview = (CardView) view;
    cardview.setEnabled(false);

    // Create a new intent to send data from this MainActivity to the CardViewDetails
    // Activity.
    Intent intent = new Intent(this,CardViewDetails.class);
    ListItem listItem = adapter.getItem(position);
    // Add the item object to the Intent.  The item object can be used because the
    // model class implements Parcelable so it holds all of the getters
    // that can be snagged in the next Activity with the
    // getParcelableExtra method.
    intent.putExtra("item",listItem);
    intent.putExtra("position",position);
    startActivity(intent);
    finish();
}

// SearchView
final EditText mSearchEditText = (EditText) mSearchView.findViewById(android.support.v7.appcompat.R.id.search_src_text);

    mSearchEditText.addTextChangedListener(new TextWatcher() {

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {

             final ArrayList<ListItem> filteredModelList = filter(allList, s.toString());

                if (!mSearchView.isIconified() && filteredModelList.size() == 0) {
                    Toast.makeText(MainActivity.this, "Not Found", Toast.LENGTH_SHORT).show();
                    // re-load the list so the Adapter refreshes the RecyclerView list View.
                    adapter.clear();
                    adapter.addAll(allList);
                } else if (!mSearchView.isIconified() && filteredModelList.size() > 0) {                            
                    adapter.setFilter(filteredModelList, s.toString());
                    mRecyclerView.scrollToPosition(0);
                }
            }
        }
    });

private ArrayList<ListItem> filter(List<ListItem> models, String query) {

    query = query.toLowerCase();

    final ArrayList<ListItem> filteredModelList = new ArrayList<>();
    for (ListItem listItem : models) {
        final String text = listItem.getTodo().toLowerCase();
        final String text2 = listItem.getNote1().toLowerCase();
        final String text3 = listItem.getNote2().toLowerCase();
        if (text.contains(query) || text2.contains(query) ||
            text3.contains(query)) {
            filteredModelList.add(listItem);
        }
    }
    return filteredModelList;
}

RecyclerItemClickListener:

public interface RecyclerItemClickListener {

    void onItemClick(View view, int position);
}

CardViewDetails:

public class CardViewDetails extends AppCompatActivity {

private int position;
private SQLiteDB helper;
List<ListItem> listItems;
private CardView cardview;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_details);

    final CardView cardView = (CardView) findViewById(R.id.dets);

    // Create a variable for the skychill footer text.
    final TextView skychilltext5;

    // A db helper instance is needed for the removeItem() below
    // when the user Longclicks the skycard for deletion.
    helper = new SQLiteDB(this);

    // Get the position of the clicked on R. list CardView from
    // the MainActivity's intent bundle.
    Bundle extras = getIntent().getExtras();
    if (extras != null) {
        // get the CardView item using the int position from the
        // MainActivity's onItemClick() and the putExtra in the intent.
        position = extras.getInt("position",0); // 0 is default value
    }

    cb2 = (TextView) findViewById(R.id.cb2);

    helper = new SQLiteDB(this);
    listItems = new ArrayList<>();
    listItems = helper.getAllDBItems(); 

    cb2.setText(listItems.get(position).getTodo());

    ...

}   

Solution

  • After applying filter the sql DB (getAllDBItems ) data remain same. You are passing only position to CardViewDetail. And the sql data is of original list.

    You should pass your ListItem as parcelable to CardViewDetails instead of position. your problem will be solved.