I am trying to create a custom ArrayAdapter that filters by "contains" instead of by "startswith". I have seen that there are similar questions, what's more, I made my custom ArrayAdapter out of those posts (like this one AutoCompleteTextView not completing words inside parentheses, or this other Change AutoCompleteTextView filter from "startsWith" to "Contains"?).
However I am getting an UnsupportedOperationException when calling clear() in publishResults. Does anyone knows why?
Here is my ArrayAdapter:
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.TextView;
import com.example.osmdroid.R;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class AutoSuggestAdapterNew<T> extends ArrayAdapter<String> {
Context context;
int resource, textViewResourceId;
List<String> items, tempItems, suggestions;
public AutoSuggestAdapterNew(Context context, int resource, int
textViewResourceId, List<String> items) {
super(context, resource, textViewResourceId, items);
this.context = context;
this.resource = resource;
this.textViewResourceId = textViewResourceId;
this.items = items;
tempItems = new ArrayList<String>(items);// this makes the difference.
suggestions = new ArrayList<String>();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.autocompletestreets_layout, parent, false);
}
String name = items.get(position);
if (name != null) {
TextView lblName = (TextView) view.findViewById(R.id.autoCompleteStreets);
if (lblName != null)
lblName.setText(name);
}
return view;
}
@Override
public Filter getFilter() {
return nameFilter;
}
/**
* Custom Filter implementation for custom suggestions we provide.
*/
Filter nameFilter = new Filter() {
@Override
public CharSequence convertResultToString(Object resultValue) {
String str = (String) resultValue;
return str;
}
@Override
protected FilterResults performFiltering(CharSequence constraint) {
if (constraint != null) {
suggestions.clear();
FilterResults filterResults = new FilterResults();
for (String name : tempItems) {
if (name.toLowerCase().contains(constraint.toString().toLowerCase())) {
suggestions.add(name);
}
}
/*String[] stringSuggestions = new String[suggestions.size()];
stringSuggestions = suggestions.toArray(stringSuggestions);*/
filterResults.values = suggestions;
filterResults.count = suggestions.size();
return filterResults;
} else {
return new FilterResults();
}
}
@Override
protected void publishResults(CharSequence constraint, FilterResults
results) {
List<String> filterList = (ArrayList<String>) results.values;
if (results != null && results.count > 0) {
clear();
for (String name : filterList) {
add(name);
notifyDataSetChanged();
}
}
}
};
}
EDIT: I discovered that I was passing an String array like Arrays.asList which returns a fixed-size list. Therefore I used new LinkedList(Arrays.asList()) and my error disappeared. However I am getting now a ConcurrentModificationException. These are my logs:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.osmdroid, PID: 20901
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.next(ArrayList.java:860)
at com.example.osmdroid.Datos.AutoSuggestAdapterNew$1.publishResults(AutoSuggestAdapterNew.java:97)
at android.widget.Filter$ResultsHandler.handleMessage(Filter.java:284)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
performFiltering(CharSequence constraint) Invoked in a worker thread to filter the data according to the constraint.
so use suggestions
in publishResults
instead of performFiltering
or create a new list in performFiltering
like this
@Override
protected FilterResults performFiltering(CharSequence constraint) {
if (constraint != null) {
final List<String> suggestions = new ArrayList<String>();
FilterResults filterResults = new FilterResults();
for (String name : tempItems) {
if (name.toLowerCase().contains(constraint.toString().toLowerCase())) {
suggestions.add(name);
}
}
/*String[] stringSuggestions = new String[suggestions.size()];
stringSuggestions = suggestions.toArray(stringSuggestions);*/
filterResults.values = suggestions;
filterResults.count = suggestions.size();
return filterResults;
} else {
return new FilterResults();
}
}