How to filter ListView using getFilter() in BaseAdapter
Asked Answered
A

3

4

In my application I have create a custom list view and I want to implement a filter so that the list can be filtered according to the text entered in the EditText. I am using a BaseAdapter as a separate class and I am calling that class in my Main Activity. I have also implemented the addTextChangedListener() in my main activity and I have also implemented the getFilter() in my BaseAdapter class. But I don't know how can I use getFilter() and can filter my list accordingly. In the list I am adding the values from a JSON URL. Please help me in letting me know that how can I use the getFilter() in order to filter my List.

The code of Activity class:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    lv = (ListView)findViewById(R.id.listView1);
    et1 = (EditText)findViewById(R.id.editText1);
    inflator = getLayoutInflater();
    et1.addTextChangedListener(this);
    JsonParser jParser = new JsonParser();
    JSONObject json = jParser.getJSONfromUrl(url);
    try
    {
        JSONArray explore = json.getJSONArray("explore");
        for(int i=0; i<explore.length(); i++)
        {
            JSONObject exp = explore.getJSONObject(i);
            list.add(exp.getString("username"));
        }
    }
    catch(JSONException e)
    {
        e.printStackTrace();
    }

    srchadptr = new SearchAdapter(this, inflator, list);
    lv.setAdapter(srchadptr);
}

public void afterTextChanged(Editable s) {
    // TODO Auto-generated method stub
    srchadptr.getFilter().filter(s);
}

public void beforeTextChanged(CharSequence s, int start, int count,
        int after) {
    // TODO Auto-generated method stub

}

public void onTextChanged(CharSequence s, int start, int before, int count) {
    // TODO Auto-generated method stub

}

The code of BaseAdapter class:

public class SearchAdapter extends BaseAdapter implements Filterable {

    Context context;
    LayoutInflater inflater;
    Button btn;
    View vw;
    ArrayList<String> list = new ArrayList<String>();

    public SearchAdapter(Context context,   LayoutInflater inflater, ArrayList<String> list) {
        // TODO Auto-generated constructor stub
        this.context = context;
        this.inflater = inflater;
        this.list = list;
    }

    /*public CharSequence filter(CharSequence cs) {
        return cs;
    }*/

    public int getCount() {
        // TODO Auto-generated method stub
        return list.size();
    }

    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }



    public View getView(final int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        LinearLayout ll = (LinearLayout) vw;
        final EditText edt = ((EditText)ll.getChildAt(0));
        vw = inflater.inflate(R.layout.list_items, null);
        ImageView img = (ImageView)vw.findViewById(R.id.imageView1);
        TextView tv = (TextView)vw.findViewById(R.id.textView1);
        btn = (Button)vw.findViewById(R.id.button1);
        tv.setText(String.valueOf(list.get(position)));
        btn.setText(String.valueOf(list.get(position)));
        btn.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                // TODO Auto-generated method stub
                Toast.makeText(context, list.get(position), Toast.LENGTH_LONG).show();
            }
        });
        return vw;
    }

    public android.widget.Filter getFilter() {
        // TODO Auto-generated method stub
        return new android.widget.Filter() {

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                // TODO Auto-generated method stub

            }

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                // TODO Auto-generated method stub
                return null;
            }
        };
    }
}

Thanks in advance...

Anatomy answered 17/9, 2012 at 9:30 Comment(9)
#8678663Immensity
I have already viewed the link but still it was of no use for me. one thing more my getFlter() is not accepting @Override it shows an error. so please provide me a basic solution.Anatomy
good to know that a working example is of no use to you!!!!Immensity
@Abhishek If you would have google for @Override problem you might have got many solution ..one is to change the compiler to 1.6 from 1.5...from project-properties-java compilerLibratory
Need to call notifyDataSetChanged() APIBlazonry
my compiler is already on 1.5 still I am not able to add the @Override. please help...Anatomy
I just have to write the nptifyDataSetChanged()? and where should I write this? please provide me some basic tutorial.. I can't understand with only one line of code...Anatomy
@OmarAbdan I am trying to do the same here but I can't... [Implementing Search Filter in Adapter Class which parses a json array ](#57135456)Lutyens
May I have help here? #57135456Lutyens
C
10

i hope this example could help you

in the Main_Activity

    EditText etSearch;
    BaseAdapterFilterable adapter;

    etSearch.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                // Listview name of the class
                Listview.this.adapter.getFilter().filter(s);
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count,
                    int after) {
                // TODO Auto-generated method stub

            }

            @Override
            public void afterTextChanged(Editable s) {
                // TODO Auto-generated method stub

            }
        });

in your adapter put this class to use it in getfilter method

public class filter_here extends Filter{

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            // TODO Auto-generated method stub

            FilterResults Result = new FilterResults();
            // if constraint is empty return the original names
            if(constraint.length() == 0 ){
                Result.values = Original_Names;
                Result.count = Original_Names.size();
                return Result;
            }

            ArrayList<String> Filtered_Names = new ArrayList<String>();
            String filterString = constraint.toString().toLowerCase();
            String filterableString;

            for(int i = 0; i<Original_Names.size(); i++){
                filterableString = Original_Names.get(i);
                if(filterableString.toLowerCase().contains(filterString)){
                    Filtered_Names.add(filterableString);
                }
            }
            Result.values = Filtered_Names;
            Result.count = Filtered_Names.size();

            return Result;
        }

        @Override
        protected void publishResults(CharSequence constraint,FilterResults results) {
            // TODO Auto-generated method stub
            Names = (ArrayList<String>) results.values;
            notifyDataSetChanged();
        }

    }

also in your adapter return instance from filter_here class

@Override
    public Filter getFilter() {
        // TODO Auto-generated method stub
        return filter;
    }
Chuddar answered 16/1, 2013 at 13:4 Comment(4)
What do you mean by the last line: "also in your adapter return instance from filter_here class"? Where need to add this return filter?Revile
@Revile in your adapter constructor initialize object from filter_here class "filter_here filter = new filter_here();" override getfilter method and return filterChuddar
@OmarAbdan Can you please help with this: #20524917Stacystadholder
In your Adapter just put the method above beside getView().... ----------getView End--------- @Override public Filter getFilter() { // TODO Auto-generated method stub return filter_here; } --------------adapter class end------------Unfamiliar
H
2

In your BaseAdapter, store two copies of the list, one original, and one filtered. And change all references in your BaseAdapter, to only use the filtered list.

1) in your activity, activate the filter on your ListView: lv.setTextFilterEnabled(true);

2) in your textWatcher, trigger the filter on your listadapter srchadptr.getFilter().filter(s)

3) Update your baseadapter to store two copies of the data, and change references to refer to the filtered list instead of the original list.

public class SearchAdapter extends BaseAdapter implements Filterable {

List<String> list = new ArrayList<String>();
List<String> listFiltered = new ArrayList<String>();

public SearchAdapter(Context context, ArrayList<String> list) {
    this.context = context;
    this.inflater = LayoutInflater.from(context)
    this.list = list;
    this.listFiltered=list;
}

public int getCount() {
    return listFiltered.size();//note the change
}

public Object getItem(int position) {
    return listFiltered.get(position);//note the change
}

//only altered lines shown in this function (change ``list`` to ``listFiltered``)
public View getView(final int position, View convertView, ViewGroup parent) {
    tv.setText(String.valueOf(listFiltered.get(position)));
    btn.setText(String.valueOf(listFiltered.get(position)));
    btn.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            Toast.makeText(context, listFiltered.get(position), Toast.LENGTH_LONG).show();
        }
    });
}

//now write your filter function

@Override
public Filter getFilter() {
    return new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults results = new FilterResults();

            if (constraint == null || constraint.length() == 0) {
                //no constraint given, just return all the data. (no search)
                results.count = list.size();
                results.values = list;
            } else {//do the search
                List<String> resultsData = new ArrayList<>();
                String searchStr = constraint.toString().toUpperCase();
                for (String s : list)
                    if (s.toUpperCase().contains(searchStr)) resultsData.add(s);
                results.count = resultsData.size();
                results.values = resultsData;
            }

            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            listFiltered = (ArrayList<String>) results.values;
            notifyDataSetChanged();
        }
    };
}
Hammerskjold answered 16/3, 2016 at 10:30 Comment(0)
D
0

I find working with filters not all that convenient.. How i do it is:

        ((EditText)findViewById(R.id.etSearch)).addTextChangedListener(new TextWatcher(){

        private boolean mCountIncreased;
        @Override
        public void afterTextChanged(Editable s) {

            if (s.toString().length() == 0){
                mDisplayedList.clear();
                mDisplayedList.addAll(mFullList);
                mListAdapter.notifyDataSetChanged();
                return;
            }

            if (mCountIncreased){
                mDisplayedList.clear();
                mDisplayedList.addAll(mFullList);
            }

            List<Item> toRemove = new ArrayList<Item>();
            for (Item item : mDisplayedList){
                if (someCondition)
                        toRemove.add(currency);
                }
            }

            mDisplayedList.removeAll(toRemove);
            mListAdapter.notifyDataSetChanged();
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            mCountIncreased = after <= count;
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {}

    });
}

Note that you'll have to change your adapter to work with the mDisplayedList instead of the mFullList.. and that's it.

This might give some overhead when your list contains ALOT of entries.. but i've worked like this with a list of +-300 items and i didn't notice anything.

Hope it helps, Vlad

Dongola answered 21/8, 2013 at 14:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.