Search code examples
javaandroidandroid-activityandroid-listviewandroid-listfragment

Filter list not reappearing after empty view shown


For some reason after being shown an empty view for no matching items, my list view won't reappear after removing all text from the search view.

Within my adapter class, AFAIK .clear() in mData.clear(); needs to change to something else but I don't know what to.

ItemListAdapter class

public class ItemListAdapter extends BaseAdapter implements Filterable {

    private List<Victoria> mData;
    private List<Victoria> mFilteredData;
    private LayoutInflater mInflater;
    private ItemFilter mFilter;

    public ItemListAdapter (List<Victoria> data, Context context) {
        mData = data;
        mFilteredData = new ArrayList(mData);
        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(mFilteredData.get(position).getItem());
        holder.description.setText(mFilteredData.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
     */
    /**
     * <p>An array filter constrains the content of the array adapter with
     * a prefix. Each item that does not start with the supplied prefix
     * is removed from the list.</p>
     */
    private class ItemFilter extends Filter {
        @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<Victoria> resultList = new ArrayList<Victoria>();
                for (Victoria str : mData) {
                    if (str.getItemDescription().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) {
                //Make list invisible
                //Make text view visible
                mFilteredData.clear();
                notifyDataSetInvalidated();
            } else {
                mFilteredData = (ArrayList<Victoria>)results.values;
                notifyDataSetChanged();
            }
        }
    }
}

Before filtering enter image description here

After filtering with an invalid character enter image description here

After clearing search view and trying to show list again enter image description here


Solution

  • Couple small fixes should get things working right for you. First, mData and mFilteredData data should be two different instances at all times. In the constructor, have mFilteredData be a new instance copied from mData

    mFilteredData = new ArrayList(mData);
    

    Additionally in the Filter, you'll need to update the corresponding code to the follow:

    if (TextUtils.isEmpty(constraint)) {
        results.count = mData.size();
        results.values = new ArrayList(mData);
    }
    

    Then your getView() method should be pulling from mFilteredData instead of mData. Ideally though, the getView() method should be using the getItem(position) method to access the data. That way, if you change implementation details of where the data is accessed from, you don't have to remember to update the getView() method separately.

    Finally as a side note, your filtering code works only because the adapter does not mutate mFilteredData or mData. Normally, one must heavily synchronize the filtering process and other parts of the adapter because performFiltering() occurs on a background thread. If you plan on adding support for modifying the adapter's data after constructing...then you'll need to start adding synchronized blocks.