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.java
final AppInfoAdapter adapter = new AppInfoAdapter(this, Utilities.getSystemFilteredApplication(this), getPackageManager());
public void onTextChanged(CharSequence s, int start, int before,
int count) {
adapter.getFilter().filter(s); //Filter from my adapter
adapter.notifyDataSetChanged(); //Update my view
}
AppInfoAdapter.java
package com.example.permission;
import java.util.List;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;
public class AppInfoAdapter extends BaseAdapter implements Filterable{
private Context mContext;
private List mListAppInfo;
PackageManager mPackManager;
public AppInfoAdapter(Context c, List list, PackageManager pm) {
mContext = c;
mListAppInfo = list;
mPackManager = pm;
}
public int getCount() {
return mListAppInfo.size();
}
public Object getItem(int position) {
return mListAppInfo.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
// get the selected entry
ApplicationInfo entry = (ApplicationInfo) mListAppInfo.get(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;
}
public Filter getFilter() {
// TODO Auto-generated method stub
return null;
}
}
EDIT: Edited the code and added full AppInfoAdapter.java
in your adapter put this class to use it in getfilter method
//this is a simple class that filtering the ArrayList of strings used in adapter
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();
}
}
return instance from it in getfilter
@Override
public Filter getFilter() {
// TODO Auto-generated method stub
return filter;
}
this almost got me killed :)
- implement your BaseAdapter like this:
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
}
});
You need to return an instance of a Filter. To write a filter, subclass Filter and implement performFiltering and publishResults. See the docs.
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;
}
}
General procedure
- Enable text filtering on your ListView
- Change your baseadapter to store two copies of the list, one original, one filtered.
- Change all access references in your BaseAdapter to refer to the Filtered list, not the original.
- Implement your Filter function in BaseAdapter.
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();
}
};
}
}
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 .
extend your class with ArrayAdapter,then override methods,and create object of filter class and return with it.
来源:https://stackoverflow.com/questions/11619874/how-to-implement-getfilter-on-a-baseadapter