user782104
user782104

Reputation: 13555

The clear() in custom listview adapter also updates the list data

I am working on a listview filter, that means, there is a editbox, if I type in some keywords , the listview data will change accordingly. To begin with, there is a dataset.

private ArrayList<PostItem> postList;

Assuming the list is already fill with data, here is the adapter with filtering:

private class PostAdapter extends ArrayAdapter<PostItem> implements
        Filterable {

    public PostAdapter(Context context, int resource, List<PostItem> items) {
        super(context, resource, items);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View v = convertView;

        if (v == null) {
            LayoutInflater vi;
            vi = LayoutInflater.from(getContext());
            v = vi.inflate(R.layout.post_item, parent, false);
        }

        PostItem post = getItem(position);

        if (post != null) {
            TextView title = (TextView) v.findViewById(R.id.postTitle);
            TextView date = (TextView) v.findViewById(R.id.postDate);

            v.setTag(post.id);
            title.setText(Html.fromHtml(post.title));
            date.setText(post.name + " "
                    + getResources().getString(R.string.post_on) + " "
                    + post.date);
        }

        return v;

    }

    @Override
    public Filter getFilter() {

        Filter filter = new Filter() {

            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence constraint,
                    FilterResults results) {

                ArrayList<PostItem> filteredList = (ArrayList<PostItem>)results.values;

                clear();

                for (PostItem item :filteredList) {
                    add(item);
                }
            }

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults results = new FilterResults();
                ArrayList<PostItem> filteredArray = new ArrayList<PostItem>();

                constraint = constraint.toString().toLowerCase();

                for (PostItem item : postList) {
                    if (item.title.toLowerCase().contains(constraint)) {
                        filteredArray.add(item);
                    }
                }

                results.count = filteredArray.size();
                results.values = filteredArray;
                return results;
            }
        };

        return filter;
    }

}

The problem is , clear() function will also remove all the item contains in postList and insert all the latest filtered result. How to fix it? I tried to have a copied variable e.g. copyPostList = postList but still the same. Thanks for helping

Update: More explanation:

  1. First, The postList has item "abc";

  2. Then, Type in "ab", the list show "abc", which is correct

  3. After that, Type in "xyz", the list show nothing, which is correct

  4. Finally, Type in "abc", the list show nothing, which is incorrect

Upvotes: 0

Views: 2391

Answers (2)

user782104
user782104

Reputation: 13555

Final code , add the filtering and getView for my case

    private class PostAdapter extends ArrayAdapter<PostItem> implements Filterable {

    private ArrayList<PostItem> fullList;
    private ArrayList<PostItem> mOriginalValues;        
    private ArrayFilter mFilter;

    public PostAdapter(Context context, int resource, List<PostItem> objects) {
        super(context, resource, objects);
        fullList = (ArrayList<PostItem>) objects;
        mOriginalValues = new ArrayList<PostItem>(fullList);

    }

    @Override
    public void add(PostItem object) {
        super.add(object);
        fullList.add(object);
        mOriginalValues.add(object);
    }

    @Override
    public void clear() {
        super.clear();
        fullList.clear();
        mOriginalValues.clear();
    }

    @Override
    public int getCount() {
        return fullList.size();
    }

    @Override
    public PostItem getItem(int position) {
        return fullList.get(position);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View v = convertView;

        if (v == null) {
            LayoutInflater vi;
            vi = LayoutInflater.from(getContext());
            v = vi.inflate(R.layout.post_item, parent, false);
        }

        PostItem post = getItem(position);

        if (post != null) {
            TextView title = (TextView) v.findViewById(R.id.postTitle);
            TextView date = (TextView) v.findViewById(R.id.postDate);

            v.setTag(post.id);
            title.setText(Html.fromHtml(post.title));
            date.setText(post.name + " "
                    + getResources().getString(R.string.post_on) + " "
                    + post.date);
        }

        return v;
    }

    @Override
    public Filter getFilter() {
        if (mFilter == null) {
            mFilter = new ArrayFilter();
        }
        return mFilter;
    }


    private class ArrayFilter extends Filter {

        @Override
        protected FilterResults performFiltering(CharSequence prefix) {
            FilterResults results = new FilterResults();
            ArrayList<PostItem> list =  new ArrayList<PostItem>();

            if (mOriginalValues == null) {
                mOriginalValues = new ArrayList<PostItem>(fullList);
            }

            for (PostItem item : mOriginalValues) {
                if (item.title.toLowerCase().contains(prefix.toString().toLowerCase())) {
                    list.add(item);
                }
            }

            results.values = list;
            results.count = list.size();
            return results;
        }

        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {

            if (results.values != null) {
                fullList = (ArrayList<PostItem>) results.values;
            } else {
                fullList = new ArrayList<PostItem>();
            }
            if (results.count > 0) {
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }
    }
}

Thanks for helping

Upvotes: 0

Ilya Demidov
Ilya Demidov

Reputation: 3305

public class AutoCompleteAdapter extends ArrayAdapter<String> implements Filterable {

    private ArrayList<String> fullList;
    private ArrayList<String> mOriginalValues;
    private ArrayFilter mFilter;

    public AutoCompleteAdapter(Context context, int resource, List<String> objects) {

        super(context, resource, objects);
        fullList = (ArrayList<String>) objects;
        mOriginalValues = new ArrayList<String>(fullList);

    }

    @Override
    public void add(String object) {
        super.add(object);
        fullList.add(object);
        mOriginalValues.add(object);
    }

    @Override
    public void clear() {
        super.clear();
        fullList.clear();
        mOriginalValues.clear();
    }

    @Override
    public int getCount() {
        return fullList.size();
    }

    @Override
    public String getItem(int position) {
        return fullList.get(position);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        TextView view = (TextView) super.getView(position, convertView, parent);
        view.setEllipsize(TextUtils.TruncateAt.START);
        return view;
    }

    @Override
    public Filter getFilter() {
        if (mFilter == null) {
            mFilter = new ArrayFilter();
        }
        return mFilter;
    }


    private class ArrayFilter extends Filter {

        @Override
        protected FilterResults performFiltering(CharSequence prefix) {
            FilterResults results = new FilterResults();

            if (mOriginalValues == null) {
                mOriginalValues = new ArrayList<String>(fullList);
            }
            ArrayList<String> list = new ArrayList<String>(mOriginalValues);
            results.values = list;
            results.count = list.size();


            return results;
        }

        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {

            if (results.values != null) {
                fullList = (ArrayList<String>) results.values;
            } else {
                fullList = new ArrayList<String>();
            }
            if (results.count > 0) {
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }
    }
}

Check it out. this adapter works great. Good luck.

Upvotes: 3

Related Questions