I am trying to implement a getFilter() on a base adapter to filter out search results on a List. Is there any example of how to implement a getFilter()?
MainActivity
General procedure
Step 1:
listview.setTextFilterEnabled(true);
Step 2:
public class AppInfoAdapter extends BaseAdapter implements Filterable{
private List mListAppInfo;
private List mListAppInfoFiltered;
public AppInfoAdapter(Context c, List list, PackageManager pm) {
mContext = c;
mListAppInfo = list;
mPackManager = pm;
mPackManagerFiltered = pm; //added line
}
Step 3:
public int getCount() {
return mListAppInfoFiltered.size();
}
public Object getItem(int position) {
return mListAppInfoFiltered.get(position);
}
public View getView(int position, View convertView, ViewGroup parent) {
// get the selected entry
ApplicationInfo entry = (ApplicationInfo) mListAppInfoFiltered.get(position);
}
Step 4: I am not sure what type your list is, so assuming a list of String:
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint == null || constraint.length() == 0) {
//no search, so just return all the data
results.count = mListAppInfo.size();
results.values = mListAppInfo;
} else {//do the search
List<String> resultsData = new ArrayList<>();
String searchStr = constraint.toString().toUpperCase();
for (String s : mListAppInfo)
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) {
mListAppInfoFiltered = (ArrayList<MyObject>) results.values;
notifyDataSetChanged();
}
};
}
}
You need to return an instance of a Filter
. To write a filter, subclass Filter
and implement performFiltering
and publishResults
. See the docs.
extend your class with ArrayAdapter,then override methods,and create object of filter class and return with it.
this almost got me killed :)
define an ArrayList of List in your public adapter class which is gonna contain temporary items of your Original List.
public class MyAdapter extends BaseAdapter implements Filterable{
public static ArrayList<String> temporarylist;
public static ArrayList<String> OriginalList;
private Activity activity;
public MyAdapter(Activity activity, ArrayList<String> OriginalList) {
super();
this.activity=activity;
this.OriginalList = OriginalList;
temporarylist=OriginalList;
}
.
.
.
create getFilter() method with the following code[as an example]:
public Filter getFilter() {
Filter filter = new Filter() {
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
temporarylist=(ArrayList<String>)results.values;
notifyDataSetChanged();
}
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
ArrayList<String> FilteredList= new ArrayList<String>();
if (constraint == null || constraint.length() == 0) {
// No filter implemented we return all the list
results.values = OriginalList;
results.count = OriginalList.size();
}
else {
for (int i = 0; i < OriginalList.size(); i++) {
String data = OriginalList.get(i);
if (data.toLowerCase().contains(constraint.toString())) {
FilteredList.add(data);
}
}
results.values = FilteredList;
results.count = FilteredList.size();
}
return results;
}
};
return filter;
}
And finally in your activity for your EditText:
MyAdapter adapter;
ArrayList<String> items;
ListView list = (ListView) findViewById(R.id.list);
items = new ArrayList<String>();
for (int i=0;i<30;i++){
items.add("Hello world "+String.valueof(i));
}
adapter = new GameAdapter(this, items);
list.setAdapter(adapter);
EditText inputSearch = (EditText) findViewById(R.id.Search_txt);
inputSearch.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
// When user changed the Text
MyActivity.this.adapter.getFilter().filter(cs);
}
@Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
}
});
Can you post your full AppInfoAdapter
? Also is there any reason extending from BaseAdapter
and not ArrayAdapter
? If you have an ArrayList
of objects, use ArrayAdapter
, it already implements Filterable
interface.
Actually you are using a List
, your adapter can be rewritten to extends ArrayAdapter
which already is Filterable
.
public class AppInfoAdapter extends ArrayAdapter<ApplicationInfo> {
private Context mContext;
PackageManager mPackManager;
public AppInfoAdapter(Context c, List<ApplicationInfo> list, PackageManager pm) {
super(c, 0, new ArrayList<ApplicationInfo>());
mContext = c;
mPackManager = pm;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// get the selected entry
ApplicationInfo entry = (ApplicationInfo) getItem(position);
// reference to convertView
View v = convertView;
// inflate new layout if null
if(v == null) {
LayoutInflater inflater = LayoutInflater.from(mContext);
v = inflater.inflate(R.layout.layout_appinfo, null);
}
// load controls from layout resources
ImageView ivAppIcon = (ImageView)v.findViewById(R.id.ivIcon);
TextView tvAppName = (TextView)v.findViewById(R.id.tvName);
TextView tvPkgName = (TextView)v.findViewById(R.id.tvPack);
// set data to display
ivAppIcon.setImageDrawable(entry.loadIcon(mPackManager));
tvAppName.setText(entry.loadLabel(mPackManager));
tvPkgName.setText(entry.packageName);
// return view
return v;
}
}
getFilter() can be override in adapters and return the filter object which contains filtered list . There are two key methods in Filter() class; performFiltering and publishResults. The first method performs the filtering in worker thread and the later one return filtered list of objects.
You can refer to sample code below
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
// TODO Auto-generated method stub
if (results.count == 0) {
notifyDataSetInvalidated();
}else{
mListAppInfo = (ArrayList<SampleItem>) results.values;
notifyDataSetChanged();
}
}
@Override
protected FilterResults performFiltering(CharSequence constraint) {
// TODO Auto-generated method stub
FilterResults results = new FilterResults();
if (constraint == null || constraint.length() == 0) {
results.values = mListAppInfo;
results.count = mListAppInfo.size();
}else{
ArrayList<SampleItem> filter_items = new ArrayList<>();
for (SampleItem item : mListAppInfo) {
if (item.getItemName().toLowerCase().startsWith(constraint.toString().toLowerCase())) {
filter_items.add(item);
}
}
results.values = filter_items ;
results.count = filter_items.size();
}
return results;
}
};
}
Hope you find it useful .