I'm trying to get my list to show all my items again whenever I cancel a search from my search view but for some strange reason, the list gets stuck with the results only from the previous search. Does anyone know what is wrong with my code and how to fix this? I believe something is wrong with the filter related code but I don't know what it is.
FilterListFragment.java
public class ItemListAdapter extends BaseAdapter implements Filterable {
private List<Item> mData;
private List<Item> mFilteredData;
private LayoutInflater mInflater;
private ItemFilter mFilter;
public ItemListAdapter (List<Item> data, Context context) {
mData = data;
mFilteredData = data;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return mFilteredData.size();
}
@Override
public String getItem(int position) {
return mFilteredData.get(position).getItem();
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_row, parent, false);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.item_title);
holder.description = (TextView) convertView.findViewById(R.id.item_description);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.title.setText(mData.get(position).getItem());
holder.description.setText(mData.get(position).getItemDescription());
return convertView;
}
@Override
public Filter getFilter() {
if (mFilter == null) {
mFilter = new ItemFilter();
}
return mFilter;
}
/**
* View holder
*/
static class ViewHolder {
private TextView title;
private TextView description;
}
/**
* Filter for filtering list items
*/
private class ItemFilter extends Filter {
/**
* Invoked on a background thread. This is where all the filter logic should go
* @param constraint the constraint to filter on
* @return the resulting list after applying the constraint
*/
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (TextUtils.isEmpty(constraint)) {
results.count = mData.size();
results.values = mData;
} else {
//Create a new list to filter on
List<Item> resultList = new ArrayList<Item>();
for (Item str : mData) {
if (str.getItem().toLowerCase().contains(constraint.toString().toLowerCase())) {
resultList.add(str);
}
}
results.count = resultList.size();
results.values = resultList;
}
return results;
}
/**
* Runs on ui thread
* @param constraint the constraint used for the result
* @param results the results to display
*/
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results.count == 0) {
notifyDataSetInvalidated();
} else {
mFilteredData = (ArrayList<Item>)results.values;
notifyDataSetChanged();
}
}
}
}
List in normal state
List in filtered state
You are operating on the original data instead of filtered data. You should maintain a reference to original data and use the filtered data for all other purposes. So that the original data is displayed when search is cleared.
Replace all usages of mData
with mFilteredData
as below and only use the original data to generate the filtered data:
private List<String> mData;
private List<String> mFilteredData;
private LayoutInflater mInflater;
private ItemFilter mFilter;
public ItemListAdapter (List<String> data, Context context) {
mData = data;
mFilteredData = data;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return mFilteredData.size();
}
@Override
public String getItem(int position) {
return mFilteredData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
String strItem = mFilteredData.get(position);
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_row, parent, false);
holder = new ViewHolder();
holder.mTvItem = (TextView) convertView.findViewById(R.id.tv_item);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.mTvItem.setText(strItem);
return convertView;
}
@Override
public Filter getFilter() {
if (mFilter == null) {
mFilter = new ItemFilter();
}
return mFilter;
}
/**
* View holder
*/
static class ViewHolder {
private TextView mTvItem;
}
/**
* Filter for filtering list items
*/
private class ItemFilter extends Filter {
/**
* Invoked on a background thread. This is where all the filter logic should go
* @param constraint the constraint to filter on
* @return the resulting list after applying the constraint
*/
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (TextUtils.isEmpty(constraint)) {
results.count = mData.size();
results.values = mData;
} else {
//Create a new list to filter on
List<String> resultList = new ArrayList<>();
for (String str : mData) {
if (str.toLowerCase().contains(constraint.toString().toLowerCase())) {
resultList.add(str);
}
}
results.count = resultList.size();
results.values = resultList;
}
return results;
}
/**
* Runs on ui thread
* @param constraint the constraint used for the result
* @param results the results to display
*/
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results.count == 0) {
notifyDataSetInvalidated();
} else {
mFilteredData = (ArrayList<String>)results.values;
notifyDataSetChanged();
}
}
}