在Android中使用ArrayAdapter进行自定义筛选
我想过滤我的ListView,这是用这个ArrayAdapter填充:
package me.alxandr.android.mymir.adapters; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Set; import me.alxandr.android.mymir.R; import me.alxandr.android.mymir.model.Manga; import android.content.Context; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.Filter; import android.widget.SectionIndexer; import android.widget.TextView; public class MangaListAdapter extends ArrayAdapter<Manga> implements SectionIndexer { public ArrayList<Manga> items; public ArrayList<Manga> filtered; private Context context; private HashMap<String, Integer> alphaIndexer; private String[] sections = new String[0]; private Filter filter; private boolean enableSections; public MangaListAdapter(Context context, int textViewResourceId, ArrayList<Manga> items, boolean enableSections) { super(context, textViewResourceId, items); this.filtered = items; this.items = filtered; this.context = context; this.filter = new MangaNameFilter(); this.enableSections = enableSections; if(enableSections) { alphaIndexer = new HashMap<String, Integer>(); for(int i = items.size() - 1; i >= 0; i--) { Manga element = items.get(i); String firstChar = element.getName().substring(0, 1).toUpperCase(); if(firstChar.charAt(0) > 'Z' || firstChar.charAt(0) < 'A') firstChar = "@"; alphaIndexer.put(firstChar, i); } Set<String> keys = alphaIndexer.keySet(); Iterator<String> it = keys.iterator(); ArrayList<String> keyList = new ArrayList<String>(); while(it.hasNext()) keyList.add(it.next()); Collections.sort(keyList); sections = new String[keyList.size()]; keyList.toArray(sections); } } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; if(v == null) { LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = vi.inflate(R.layout.mangarow, null); } Manga o = items.get(position); if(o != null) { TextView tt = (TextView) v.findViewById(R.id.MangaRow_MangaName); TextView bt = (TextView) v.findViewById(R.id.MangaRow_MangaExtra); if(tt != null) tt.setText(o.getName()); if(bt != null) bt.setText(o.getLastUpdated() + " - " + o.getLatestChapter()); if(enableSections && getSectionForPosition(position) != getSectionForPosition(position + 1)) { TextView h = (TextView) v.findViewById(R.id.MangaRow_Header); h.setText(sections[getSectionForPosition(position)]); h.setVisibility(View.VISIBLE); } else { TextView h = (TextView) v.findViewById(R.id.MangaRow_Header); h.setVisibility(View.GONE); } } return v; } @Override public void notifyDataSetInvalidated() { if(enableSections) { for (int i = items.size() - 1; i >= 0; i--) { Manga element = items.get(i); String firstChar = element.getName().substring(0, 1).toUpperCase(); if(firstChar.charAt(0) > 'Z' || firstChar.charAt(0) < 'A') firstChar = "@"; alphaIndexer.put(firstChar, i); } Set<String> keys = alphaIndexer.keySet(); Iterator<String> it = keys.iterator(); ArrayList<String> keyList = new ArrayList<String>(); while (it.hasNext()) { keyList.add(it.next()); } Collections.sort(keyList); sections = new String[keyList.size()]; keyList.toArray(sections); super.notifyDataSetInvalidated(); } } public int getPositionForSection(int section) { if(!enableSections) return 0; String letter = sections[section]; return alphaIndexer.get(letter); } public int getSectionForPosition(int position) { if(!enableSections) return 0; int prevIndex = 0; for(int i = 0; i < sections.length; i++) { if(getPositionForSection(i) > position && prevIndex <= position) { prevIndex = i; break; } prevIndex = i; } return prevIndex; } public Object[] getSections() { return sections; } @Override public Filter getFilter() { if(filter == null) filter = new MangaNameFilter(); return filter; } private class MangaNameFilter extends Filter { @Override protected FilterResults performFiltering(CharSequence constraint) { // NOTE: this function is *always* called from a background thread, and // not the UI thread. constraint = constraint.toString().toLowerCase(); FilterResults result = new FilterResults(); if(constraint != null && constraint.toString().length() > 0) { ArrayList<Manga> filt = new ArrayList<Manga>(); ArrayList<Manga> lItems = new ArrayList<Manga>(); synchronized (items) { Collections.copy(lItems, items); } for(int i = 0, l = lItems.size(); i < l; i++) { Manga m = lItems.get(i); if(m.getName().toLowerCase().contains(constraint)) filt.add(m); } result.count = filt.size(); result.values = filt; } else { synchronized(items) { result.values = items; result.count = items.size(); } } return result; } @SuppressWarnings("unchecked") @Override protected void publishResults(CharSequence constraint, FilterResults results) { // NOTE: this function is *always* called from the UI thread. filtered = (ArrayList<Manga>)results.values; notifyDataSetChanged(); } } }
但是,当我在filter上调用filter('test')时,根本没有任何事情发生(或者后台线程运行,但是列表没有按照用户的要求过滤)。 我该如何解决这个问题?
这解决了我的问题。 我不确定这是最好的解决scheme,但它的工作原理。 我的项目的开源,所以随时使用任何代码,如果certificate有用:-)。
package me.alxandr.android.mymir.adapters; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Set; import me.alxandr.android.mymir.R; import me.alxandr.android.mymir.model.Manga; import android.content.Context; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.Filter; import android.widget.SectionIndexer; import android.widget.TextView; public class MangaListAdapter extends ArrayAdapter<Manga> implements SectionIndexer { public ArrayList<Manga> items; public ArrayList<Manga> filtered; private Context context; private HashMap<String, Integer> alphaIndexer; private String[] sections = new String[0]; private Filter filter; private boolean enableSections; public Manga getByPosition(int position) { return items.get(position); } public MangaListAdapter(Context context, int textViewResourceId, ArrayList<Manga> items, boolean enableSections) { super(context, textViewResourceId, items); this.filtered = items; this.items = ArrayList<Manga> items.clone(); this.context = context; this.filter = new MangaNameFilter(); this.enableSections = enableSections; if(enableSections) { alphaIndexer = new HashMap<String, Integer>(); for(int i = items.size() - 1; i >= 0; i--) { Manga element = items.get(i); String firstChar = element.getName().substring(0, 1).toUpperCase(); if(firstChar.charAt(0) > 'Z' || firstChar.charAt(0) < 'A') firstChar = "@"; alphaIndexer.put(firstChar, i); } Set<String> keys = alphaIndexer.keySet(); Iterator<String> it = keys.iterator(); ArrayList<String> keyList = new ArrayList<String>(); while(it.hasNext()) keyList.add(it.next()); Collections.sort(keyList); sections = new String[keyList.size()]; keyList.toArray(sections); } } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; if(v == null) { LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = vi.inflate(R.layout.mangarow, null); } Manga o = filtered.get(position); if(o != null) { TextView tt = (TextView) v.findViewById(R.id.MangaRow_MangaName); TextView bt = (TextView) v.findViewById(R.id.MangaRow_MangaExtra); if(tt != null) tt.setText(o.getName()); if(bt != null) bt.setText(o.getLastUpdated() + " - " + o.getLatestChapter()); if(enableSections && getSectionForPosition(position) != getSectionForPosition(position + 1)) { TextView h = (TextView) v.findViewById(R.id.MangaRow_Header); h.setText(sections[getSectionForPosition(position)]); h.setVisibility(View.VISIBLE); } else { TextView h = (TextView) v.findViewById(R.id.MangaRow_Header); h.setVisibility(View.GONE); } } return v; } @Override public void notifyDataSetInvalidated() { if(enableSections) { for (int i = items.size() - 1; i >= 0; i--) { Manga element = items.get(i); String firstChar = element.getName().substring(0, 1).toUpperCase(); if(firstChar.charAt(0) > 'Z' || firstChar.charAt(0) < 'A') firstChar = "@"; alphaIndexer.put(firstChar, i); } Set<String> keys = alphaIndexer.keySet(); Iterator<String> it = keys.iterator(); ArrayList<String> keyList = new ArrayList<String>(); while (it.hasNext()) { keyList.add(it.next()); } Collections.sort(keyList); sections = new String[keyList.size()]; keyList.toArray(sections); super.notifyDataSetInvalidated(); } } public int getPositionForSection(int section) { if(!enableSections) return 0; String letter = sections[section]; return alphaIndexer.get(letter); } public int getSectionForPosition(int position) { if(!enableSections) return 0; int prevIndex = 0; for(int i = 0; i < sections.length; i++) { if(getPositionForSection(i) > position && prevIndex <= position) { prevIndex = i; break; } prevIndex = i; } return prevIndex; } public Object[] getSections() { return sections; } @Override public Filter getFilter() { if(filter == null) filter = new MangaNameFilter(); return filter; } private class MangaNameFilter extends Filter { @Override protected FilterResults performFiltering(CharSequence constraint) { // NOTE: this function is *always* called from a background thread, and // not the UI thread. constraint = constraint.toString().toLowerCase(); FilterResults result = new FilterResults(); if(constraint != null && constraint.toString().length() > 0) { ArrayList<Manga> filt = new ArrayList<Manga>(); ArrayList<Manga> lItems = new ArrayList<Manga>(); synchronized (this) { lItems.addAll(items); } for(int i = 0, l = lItems.size(); i < l; i++) { Manga m = lItems.get(i); if(m.getName().toLowerCase().contains(constraint)) filt.add(m); } result.count = filt.size(); result.values = filt; } else { synchronized(this) { result.values = items; result.count = items.size(); } } return result; } @SuppressWarnings("unchecked") @Override protected void publishResults(CharSequence constraint, FilterResults results) { // NOTE: this function is *always* called from the UI thread. filtered = (ArrayList<Manga>)results.values; notifyDataSetChanged(); clear(); for(int i = 0, l = filtered.size(); i < l; i++) add(filtered.get(i)); notifyDataSetInvalidated(); } } }
我不觉得有必要做以上的任何事情。 重写POJO的toString()方法,如…
public String toString() { return this.getCallTitle() == null ? "" : this.getCallTitle().toLowerCase(); }
TextWatcher只是过滤和更简单的方法。
adapter.getFilter().filter(chars.toString().toLowerCase());
除非你有非常自定义的过滤,否则这个解决scheme的工作 希望这有利于他人。
我写了这个类,基本上是ArrayAdapter
一个副本,只是稍微修改一下类似于Alxandr的解决scheme,但是更加优雅。
我所做的只是将嵌套类ArrayAdapter.ArrayFilter
的filter逻辑拉到ArrayAdapter
类中以暴露它(并允许用户覆盖它)。
package com.example; /* Copyright (C) 2006 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific language governing permissions and limitations under the * License. */ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import android.content.Context; import android.util.Log; 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.TextView; /** * Slightly adopted ArrayAdapter. Basically a simple copy of ArrayAdapter with an extracted method filterObject() to * allow easy change of the filtering-behaviour. * * A concrete BaseAdapter that is backed by an array of arbitrary objects. By default this class expects that the * provided resource id references a single TextView. If you want to use a more complex layout, use the constructors * that also takes a field id. That field id should reference a TextView in the larger layout resource. * * <p> * However the TextView is referenced, it will be filled with the toString() of each object in the array. You can add * lists or arrays of custom objects. Override the toString() method of your objects to determine what text will be * displayed for the item in the list. * * <p> * To use something other than TextViews for the array display, for instance, ImageViews, or to have some of data * besides toString() results fill the views, override {@link #getView(int, View, ViewGroup)} to return the type of view * you want. * * @param <T> The class, this adapter should hold */ public class OGArrayAdapter<T> extends BaseAdapter implements Filterable { /** * Contains the list of objects that represent the data of this ArrayAdapter. The content of this list is referred * to as "the array" in the documentation. */ private List<T> mObjects; /** * Lock used to modify the content of {@link #mObjects}. Any write operation performed on the array should be * synchronized on this lock. This lock is also used by the filter (see {@link #getFilter()} to make a synchronized * copy of the original array of data. */ private final Object mLock = new Object(); /** * The resource indicating what views to inflate to display the content of this array adapter. */ private int mResource; /** * The resource indicating what views to inflate to display the content of this array adapter in a drop down widget. */ private int mDropDownResource; /** * If the inflated resource is not a TextView, {@link #mFieldId} is used to find a TextView inside the inflated * views hierarchy. This field must contain the identifier that matches the one defined in the resource file. */ private int mFieldId = 0; /** * Indicates whether or not {@link #notifyDataSetChanged()} must be called whenever {@link #mObjects} is modified. */ private boolean mNotifyOnChange = true; private Context mContext; // A copy of the original mObjects array, initialized from and then used instead as soon as // the mFilter ArrayFilter is used. mObjects will then only contain the filtered values. private ArrayList<T> mOriginalValues; private OGArrayFilter mFilter; private LayoutInflater mInflater; /** * Constructor * * @param context The current context. * @param textViewResourceId The resource ID for a layout file containing a TextView to use when instantiating * views. */ public OGArrayAdapter(Context context, int textViewResourceId) { init(context, textViewResourceId, 0, new ArrayList<T>()); } /** * Constructor * * @param context The current context. * @param resource The resource ID for a layout file containing a layout to use when instantiating views. * @param textViewResourceId The id of the TextView within the layout resource to be populated */ public OGArrayAdapter(Context context, int resource, int textViewResourceId) { init(context, resource, textViewResourceId, new ArrayList<T>()); } /** * Constructor * * @param context The current context. * @param textViewResourceId The resource ID for a layout file containing a TextView to use when instantiating * views. * @param objects The objects to represent in the ListView. */ public OGArrayAdapter(Context context, int textViewResourceId, T[] objects) { init(context, textViewResourceId, 0, Arrays.asList(objects)); } /** * Constructor * * @param context The current context. * @param resource The resource ID for a layout file containing a layout to use when instantiating views. * @param textViewResourceId The id of the TextView within the layout resource to be populated * @param objects The objects to represent in the ListView. */ public OGArrayAdapter(Context context, int resource, int textViewResourceId, T[] objects) { init(context, resource, textViewResourceId, Arrays.asList(objects)); } /** * Constructor * * @param context The current context. * @param textViewResourceId The resource ID for a layout file containing a TextView to use when instantiating * views. * @param objects The objects to represent in the ListView. */ public OGArrayAdapter(Context context, int textViewResourceId, List<T> objects) { init(context, textViewResourceId, 0, objects); } /** * Constructor * * @param context The current context. * @param resource The resource ID for a layout file containing a layout to use when instantiating views. * @param textViewResourceId The id of the TextView within the layout resource to be populated * @param objects The objects to represent in the ListView. */ public OGArrayAdapter(Context context, int resource, int textViewResourceId, List<T> objects) { init(context, resource, textViewResourceId, objects); } /** * Adds the specified object at the end of the array. * * @param object The object to add at the end of the array. */ public void add(T object) { synchronized (mLock) { if (mOriginalValues != null) { mOriginalValues.add(object); } else { mObjects.add(object); } } if (mNotifyOnChange) notifyDataSetChanged(); } /** * Adds the specified Collection at the end of the array. * * @param collection The Collection to add at the end of the array. */ public void addAll(Collection<? extends T> collection) { synchronized (mLock) { if (mOriginalValues != null) { mOriginalValues.addAll(collection); } else { mObjects.addAll(collection); } } if (mNotifyOnChange) notifyDataSetChanged(); } /** * Adds the specified items at the end of the array. * * @param items The items to add at the end of the array. */ public void addAll(T... items) { synchronized (mLock) { if (mOriginalValues != null) { Collections.addAll(mOriginalValues, items); } else { Collections.addAll(mObjects, items); } } if (mNotifyOnChange) notifyDataSetChanged(); } /** * Inserts the specified object at the specified index in the array. * * @param object The object to insert into the array. * @param index The index at which the object must be inserted. */ public void insert(T object, int index) { synchronized (mLock) { if (mOriginalValues != null) { mOriginalValues.add(index, object); } else { mObjects.add(index, object); } } if (mNotifyOnChange) notifyDataSetChanged(); } /** * Removes the specified object from the array. * * @param object The object to remove. */ public void remove(T object) { synchronized (mLock) { if (mOriginalValues != null) { mOriginalValues.remove(object); } else { mObjects.remove(object); } } if (mNotifyOnChange) notifyDataSetChanged(); } /** * Remove all elements from the list. */ public void clear() { synchronized (mLock) { if (mOriginalValues != null) { mOriginalValues.clear(); } else { mObjects.clear(); } } if (mNotifyOnChange) notifyDataSetChanged(); } /** * Sorts the content of this adapter using the specified comparator. * * @param comparator The comparator used to sort the objects contained in this adapter. */ public void sort(Comparator<? super T> comparator) { synchronized (mLock) { if (mOriginalValues != null) { Collections.sort(mOriginalValues, comparator); } else { Collections.sort(mObjects, comparator); } } if (mNotifyOnChange) notifyDataSetChanged(); } /** * {@inheritDoc} */ @Override public void notifyDataSetChanged() { super.notifyDataSetChanged(); mNotifyOnChange = true; } /** * Control whether methods that change the list ({@link #add}, {@link #insert}, {@link #remove}, {@link #clear}) * automatically call {@link #notifyDataSetChanged}. If set to false, caller must manually call * notifyDataSetChanged() to have the changes reflected in the attached view. * * The default is true, and calling notifyDataSetChanged() resets the flag to true. * * @param notifyOnChange if true, modifications to the list will automatically call {@link #notifyDataSetChanged} */ public void setNotifyOnChange(boolean notifyOnChange) { mNotifyOnChange = notifyOnChange; } private void init(Context context, int resource, int textViewResourceId, List<T> objects) { mContext = context; mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mResource = mDropDownResource = resource; mObjects = objects; mFieldId = textViewResourceId; } /** * Returns the context associated with this array adapter. The context is used to create views from the resource * passed to the constructor. * * @return The Context associated with this adapter. */ public Context getContext() { return mContext; } /** * {@inheritDoc} */ public int getCount() { return mObjects.size(); } /** * {@inheritDoc} */ public T getItem(int position) { return mObjects.get(position); } /** * Returns the position of the specified item in the array. * * @param item The item to retrieve the position of. * * @return The position of the specified item. */ public int getPosition(T item) { return mObjects.indexOf(item); } /** * {@inheritDoc} */ public long getItemId(int position) { return position; } /** * {@inheritDoc} */ public View getView(int position, View convertView, ViewGroup parent) { return createViewFromResource(position, convertView, parent, mResource); } private View createViewFromResource(int position, View convertView, ViewGroup parent, int resource) { View view; TextView text; if (convertView == null) { view = mInflater.inflate(resource, parent, false); } else { view = convertView; } try { if (mFieldId == 0) { // If no custom field is assigned, assume the whole resource is a TextView text = (TextView) view; } else { // Otherwise, find the TextView field within the layout text = (TextView) view.findViewById(mFieldId); } } catch (ClassCastException e) { Log.e("ArrayAdapter", "You must supply a resource ID for a TextView"); throw new IllegalStateException("ArrayAdapter requires the resource ID to be a TextView", e); } T item = getItem(position); if (item instanceof CharSequence) { text.setText((CharSequence) item); } else { text.setText(item.toString()); } return view; } /** * <p> * Sets the layout resource to create the drop down views. * </p> * * @param resource the layout resource defining the drop down views * @see #getDropDownView(int, android.view.View, android.view.ViewGroup) */ public void setDropDownViewResource(int resource) { this.mDropDownResource = resource; } /** * {@inheritDoc} */ @Override public View getDropDownView(int position, View convertView, ViewGroup parent) { return createViewFromResource(position, convertView, parent, mDropDownResource); } /** * Creates a new ArrayAdapter from external resources. The content of the array is obtained through * {@link android.content.res.Resources#getTextArray(int)}. * * @param context The application's environment. * @param textArrayResId The identifier of the array to use as the data source. * @param textViewResId The identifier of the layout used to create views. * * @return An ArrayAdapter<CharSequence>. */ public static ArrayAdapter<CharSequence> createFromResource(Context context, int textArrayResId, int textViewResId) { CharSequence[] strings = context.getResources().getTextArray(textArrayResId); return new ArrayAdapter<CharSequence>(context, textViewResId, strings); } /** * {@inheritDoc} */ public Filter getFilter() { if (mFilter == null) { mFilter = new OGArrayFilter(); } return mFilter; } /** * Performs filtering on the provided object and returns true, if the object should be in the filtered collection, * or false if it shouldn't. * * @param myObject The object to be inspected * @param constraint Constraint, that the object has to fulfil * @return true, if the object should be in the filteredResult, false otherwise */ protected boolean filterObject(T myObject, String constraint) { final String valueText = myObject.toString().toLowerCase(); // First match against the whole, non-splitted value if (valueText.startsWith(constraint)) { return true; } else { final String[] words = valueText.split(" "); final int wordCount = words.length; // Start at index 0, in case valueText starts with space(s) for (int k = 0; k < wordCount; k++) { if (words[k].startsWith(constraint)) { return true; } } } // No match, so don't add to collection return false; } /** * <p> * An array filter constrains the content of the array adapter with a prefix. Each item that does not start with the * supplied prefix is removed from the list. * </p> */ private class OGArrayFilter extends Filter { @Override protected FilterResults performFiltering(CharSequence prefix) { FilterResults results = new FilterResults(); if (mOriginalValues == null) { synchronized (mLock) { mOriginalValues = new ArrayList<T>(mObjects); } } if (prefix == null || prefix.length() == 0) { ArrayList<T> list; synchronized (mLock) { list = new ArrayList<T>(mOriginalValues); } results.values = list; results.count = list.size(); } else { String prefixString = prefix.toString().toLowerCase(); ArrayList<T> values; synchronized (mLock) { values = new ArrayList<T>(mOriginalValues); } final int count = values.size(); final ArrayList<T> newValues = new ArrayList<T>(); for (int i = 0; i < count; i++) { final T value = values.get(i); if (filterObject(value, prefixString)) { newValues.add(value); } } results.values = newValues; results.count = newValues.size(); } return results; } @Override protected void publishResults(CharSequence constraint, FilterResults results) { //noinspection unchecked mObjects = (List<T>) results.values; if (results.count > 0) { notifyDataSetChanged(); } else { notifyDataSetInvalidated(); } } } }
这个解决scheme的好处是它在应用程序中很漂亮,只需重写从ArrayAdapter.ArrayFilter类到ArrayAdapter中的filterObject方法即可:
public class MyAdapter extends OGArrayAdapter<OGScene> { // Do the rest of your adapter @Override protected boolean filterObject(OGScene myObject, String constraint) { // If true, the object will be in the list, if false, it will be filtered. // Do your own filtering with myObject as you desire return myObject.fulfillsConstraint(constraint); } }
我发现过滤ArrayAdapter的最好方法是创build我自己的filter类:
private class MyFilter extends Filter
然后在该函数中创build新的对象数组以在filter之后显示(您可以在class ArrayAdapter
的源代码中find好的实现)
@Override protected FilterResults performFiltering(CharSequence prefix)
现在的诀窍就是用这种方法
@Override protected void publishResults(CharSequence constraint, FilterResults results)
当你使用arrays适配器时,你不能这样做:
myAdapterData = results.values
从那时起,你将数据从超级数据中断开,你必须这样做以保持对超级原始数据数组的引用:
data.clear(); data.addAll((List<YourType>) results.values);
然后重写
用getFilter()
在你的适配器中,例如:
@Override public Filter getFilter() { if (filter == null) { filter = new MyFilter(); } return filter; }