Filtering a ListView using an ArrayAdapter without overriding getFilter method
android, android-arrayadapter, android-listview
Solution
The following question deals with exactly the same issue that I encountered. This question also gives an example of what the filtering is doing, showing the correct number of items by not showing the correct items in the list.
So it seems that this answer is wrong, despite being upvoted six times. I resolved this by not making use of the `getFilter` method of the `ArrayAdapter` at all. Rather, I create a new `ArrayAdapter` in my `TextWatcher` instance, as follows:
private TextWatcher filterTextWatcher = new TextWatcher() {
public void afterTextChanged(Editable s) {}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!s.toString().equals("")) {
List<Title> filteredTitles = new ArrayList<Title>();
for (int i=0; i<titles.size(); i++) {
if (titles.get(i).toString().contains(s)) {
filteredTitles.add(titles.get(i));
}
}
adapter = new TitleListingArrayAdapter(TitleListingActivity.this, R.id.list, filteredTitles);
listView.setAdapter(adapter);
}
else {
adapter = new TitleListingArrayAdapter(TitleListingActivity.this, R.id.list, titles);
listView.setAdapter(adapter);
}
}
};
Note that I also moved the declaration `List<Title> titles` out of `onCreate` and made it a member variable of my `Activity` class so that it is accessible inside the `onTextChanged` method of `filterTextWatcher`.
Problem
In this Stackoverflow answer, it is indicated that filtering can be accomplished in a `ListView` without overriding the `getFilter` method of the `ArrayAdapter` and instead implementing `toString` in the `POJO` class. I have tried implementing it, but the filtering is not working correctly. Although the `ListView` does filter, it doesn't show the correct items in the array. So, for example, if the filter matches a single row in the `array` then one item is shown in the `ListView`, but it is the wrong item that is shown. In this scenario, the first item of the array is always shown and not the item that actually matches the entered search text. Here is the code for my `ArrayAdapter`: ``` public class TitleListingArrayAdapter extends ArrayAdapter<Title> { private List<Title> items; private Context context; public TitleListingArrayAdapter(Context context, int textViewResourceId, List<Title> items) { super(context, textViewResourceId, items); this.items = items; this.context = context; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = convertView; if (view == null) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.titlelisting_single_row, null); } Title item = items.get(position); if (item!= null) { TextView titleView = (TextView) view.findViewById(R.id.title); if (titleView != null) { titleView.setText(item.getName()); } TextView yearView = (TextView) view.findViewById(R.id.year); if (yearView != null) { yearView.setText(String.valueOf(item.getYear())+", "); } TextView genreView = (TextView) view.findViewById(R.id.genre); if (genreView != null) { genreView.setText(item.getGenre()); } TextView authorView = (TextView) view.findViewById(R.id.author); if (authorView != null) { authorView.setText(item.getAuthor()); } RatingBar ratingView = (RatingBar) view.findViewById(R.id.rating); if (ratingView != null) { ratingView.setRating(item.getRating()); } ImageView iconView = (ImageView) view.findViewById(R.id.list_image); iconView.setImageResource(lookupResourceId(context, item.getID())); } return view; } private int lookupResourceId(Context context, String id) { String resourceName = "thumb_"+id; return context.getResources().getIdentifier(resourceName, "drawable", context.getPackageName()); } } ``` Here is the relevant section of my `Activity` code: ``` @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.listing); databaseHandler = new DatabaseHandler(this); listView = (ListView) findViewById(R.id.list); List<Title> titles = databaseHandler.getAllTitles(); adapter = new TitleListingArrayAdapter(this, R.id.list, titles); listView.setAdapter(adapter); filterText = (EditText) findViewById(R.id.filter); filterText.addTextChangedListener(filterTextWatcher); } private TextWatcher filterTextWatcher = new TextWatcher() { public void afterTextChanged(Editable s) {} public void beforeTextChanged(CharSequence s, int start, int count, int after) {} public void onTextChanged(CharSequence s, int start, int before, int count) { adapter.getFilter().filter(s.toString().toLowerCase()); } }; ``` The Title `POJO` class implements toString as follows: ``` @Override public String toString() { String name = this.getName() == null ? "" : this.getName().toLowerCase(); String year = this.getYear() == null ? "" : this.getYear().toString(); String genre = this.getGenre() == null ? "" : this.getGenre().toLowerCase(); return name + " " +year+ " "+ genre; } ``` Does anyone have any idea why the filtering is not working correctly and how I could fix it?