Hey guys I've implemented my own ArrayAdapter because I have two textviews in the single ListView item. While the filtering works fine(it shows the correct items), when I delete the text that I have typed to filter the items the ListView doesn't go to its initial state(it doesn't display all items), instead it just leaves the filtered list unchanged. Here is my filter implementation:
private class NightFilter extends Filter {
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
items = (ArrayList<NightOut>) results.values;
clear();
int count = items.size();
for (int i = 0; i < count; i++) {
NightOut pkmn = (NightOut) items.get(i);
add(pkmn);
}
}
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults result = new FilterResults();
if (constraint == null || constraint.length() == 0) {
ArrayList<NightOut> list = new ArrayList<NightOut>(nightsOut);
result.values = list;
result.count = list.size();
} else {
final ArrayList<NightOut> list = new ArrayList<NightOut>(nightsOut);
final ArrayList<NightOut> nlist = new ArrayList<NightOut>();
int count = list.size();
for (int i = 0; i < count; i++) {
final NightOut nightOut = list.get(i);
final String value = nightOut.getAddress().toLowerCase();
if (value.contains(constraint.toString().toLowerCase())) {
nlist.add(nightOut);
}
}
result.values = nlist;
result.count = nlist.size();
}
return result;
}
}
Both nightsOut and items contain the objects that i want to filter through(I assign those in the constructor). My custom adapter class extends ArrayAdapter if that's of any help.
Edit:
Added code for constructor and text filtering
public CustomArrayAdapter(Activity context, ArrayList<NightOut> nightsOut) {
super(context, R.layout.list_item, nightsOut);
this.context = context;
this.nightsOut = nightsOut;
this.items = nightsOut;
}
Search method
inputSearch.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
ViewPlacesActivity.this.adapter.getFilter().filter(cs);
}
Any idea what I'm missing?
Cheers Kyle
The way you are using nightsOut
as the source list for your ArrayAdapter
and also the source list for the filter is what is causing the problem.
In the publishResults()
method you have a call to clear()
which removes all elements from the nightsOut
list inside ArrayAdapter
since that is the list it references. You then readd only the filtered data.
Then the next time call performFiltering()
you are using nightsOut
as the source list again which only includes the filtered items.
What you want to do instead is keep a reference to your original items. You don't really need items
the way it is currently used so I would rename that to originalItems
and do the following:
public CustomArrayAdapter(Activity context, ArrayList<NightOut> nightsOut) {
super(context, R.layout.list_item, nightsOut);
this.context = context;
this.nightsOut = nightsOut;
originalItems = new ArrayList<>(nightsOut); // create a copy of nightsOut.
}
And then the filter
private class NightFilter extends Filter {
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
ArrayList<NightOut> tempList = (ArrayList<NightOut>) results.values;
clear();
addAll(tempList);
}
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults result = new FilterResults();
if (constraint == null || constraint.length() == 0) {
result.values = originalItems;
result.count = originalItems.size();
} else {
final ArrayList<NightOut> nlist = new ArrayList<NightOut>();
String lowerConstraint = constraint.toString().toLowerCase();
// loop through originalItems which always contains all items
for(NightOut nightOut : originalItems) {
final String value = nightOut.getAddress().toLowerCase();
if (value.contains(lowerConstraint)) {
nlist.add(nightOut);
}
}
result.values = nlist;
result.count = nlist.size();
}
return result;
}
}