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 .