问题
For some reason after being shown an empty view for no matching items, my list view won't reappear after removing all text from the search view.
Within my adapter class, AFAIK
.clear()
inmData.clear();
needs to change to something else but I don't know what to.
ItemListAdapter class
public class ItemListAdapter extends BaseAdapter implements Filterable {
private List<Victoria> mData;
private List<Victoria> mFilteredData;
private LayoutInflater mInflater;
private ItemFilter mFilter;
public ItemListAdapter (List<Victoria> data, Context context) {
mData = data;
mFilteredData = new ArrayList(mData);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return mFilteredData.size();
}
@Override
public String getItem(int position) {
return mFilteredData.get(position).getItem();
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_row, parent, false);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.item_title);
holder.description = (TextView) convertView.findViewById(R.id.item_description);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.title.setText(mFilteredData.get(position).getItem());
holder.description.setText(mFilteredData.get(position).getItemDescription());
return convertView;
}
@Override
public Filter getFilter() {
if (mFilter == null) {
mFilter = new ItemFilter();
}
return mFilter;
}
/**
* View holder
*/
static class ViewHolder {
private TextView title;
private TextView description;
}
/**
* Filter for filtering list items
*/
/**
* <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 ItemFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (TextUtils.isEmpty(constraint)) {
results.count = mData.size();
results.values = mData;
} else {
//Create a new list to filter on
List<Victoria> resultList = new ArrayList<Victoria>();
for (Victoria str : mData) {
if (str.getItemDescription().toLowerCase().contains(constraint.toString().toLowerCase())) {
resultList.add(str);
}
}
results.count = resultList.size();
results.values = resultList;
}
return results;
}
/**
* Runs on ui thread
* @param constraint the constraint used for the result
* @param results the results to display
*/
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results.count == 0) {
//Make list invisible
//Make text view visible
mFilteredData.clear();
notifyDataSetInvalidated();
} else {
mFilteredData = (ArrayList<Victoria>)results.values;
notifyDataSetChanged();
}
}
}
}
Before filtering
![](https://i0.wp.com/i.stack.imgur.com/LWfRW.png)
After filtering with an invalid character
![](https://i0.wp.com/i.stack.imgur.com/suyQ2.png)
After clearing search view and trying to show list again
![](https://i0.wp.com/i.stack.imgur.com/TAYZa.png)
回答1:
Couple small fixes should get things working right for you. First, mData
and mFilteredData
data should be two different instances at all times. In the constructor, have mFilteredData
be a new instance copied from mData
mFilteredData = new ArrayList(mData);
Additionally in the Filter
, you'll need to update the corresponding code to the follow:
if (TextUtils.isEmpty(constraint)) {
results.count = mData.size();
results.values = new ArrayList(mData);
}
Then your getView()
method should be pulling from mFilteredData
instead of mData
. Ideally though, the getView()
method should be using the getItem(position)
method to access the data. That way, if you change implementation details of where the data is accessed from, you don't have to remember to update the getView()
method separately.
Finally as a side note, your filtering code works only because the adapter does not mutate mFilteredData
or mData
. Normally, one must heavily synchronize
the filtering process and other parts of the adapter because performFiltering()
occurs on a background thread. If you plan on adding support for modifying the adapter's data after constructing...then you'll need to start adding synchronized
blocks.
回答2:
You are modifying the array that contains the original data, and when de Adapter
recreates the list, the array has no data.
The correct thing to do this is to create a copy of the original array, and return the copy as the result every time the list is filtered, leaving the original data untouched. A very good example can be found in the ArrayAdapter
implementation. See the source code here.
I'll include a copy of the source code here just in case:
/**
* <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 ArrayFilter 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);
final String valueText = value.toString().toLowerCase();
// First match against the whole, non-splitted value
if (valueText.startsWith(prefixString)) {
newValues.add(value);
} 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(prefixString)) {
newValues.add(value);
break;
}
}
}
}
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();
}
}
来源:https://stackoverflow.com/questions/31014764/filter-list-not-reappearing-after-empty-view-shown