Reputation:
In a simple Android app that used to use an ArrayList and an ArrayAdapter to fill an AutoCompleteTextView, I have now replaced the ArrayAdapter with a custom adapter. The reason is that I need to strip whitespace and some other characters from the entered text before searching the list (i.e., entering "O.M." should be normalised to "OM" and then the suggestions beginning with "OM" should be displayed.
I tried to do this in the following commit on GitHub: https://github.com/Natureshadow/MirWTFApp/commit/260a4deaee449cb63d3af3c446c94466b90f736c
The custom Adapter has a getFilter method that should return a custom Filter doing the normalisation, but getFilter() is never called.
What can I do to find out why it is not called, and how can I make the app use the custom Filter?
StackOverflow has some questions that describe a similar issue, but all these questions include changing the handling of the ArrayList data within the custom adapter, which I did not do.
Upvotes: 1
Views: 1372
Reputation: 5317
The solution ended up being a custom ArrayAdapter
subclass which prepends a filter before the ArrayFilter
even sees it.
The change to the main application is minimal, it just needs to instantiate the newly-christened WtfArrayAdapter
and pass its constructor an extra argument: an object reference to the object containing the normalisation method (in the current äpp’s design, that’s the MainActivity
class, a future refactor will do better):
- ArrayAdapter acronymKeys = new ArrayAdapter(this,
- android.R.layout.simple_list_item_1, sorted);
+ ArrayAdapter acronymKeys = new WtfArrayAdapter(this,
+ android.R.layout.simple_list_item_1, sorted, this);
The custom WtfArrayAdapter
must be able to call methods from ArrayFilter
(which is ArrayAdapter
’s internal private class), so it needs to belong to package android.widget;
. I’ll spare you the full imports, comments, etc. and will reproduce the important parts below:
public class WtfArrayAdapter<T> extends ArrayAdapter<T> {
New members for:
- the pre-filter normalisation method’s object
- our internal private class’ object
- the parent’s internal private class’ object (ArrayAdapter.mFilter
is private
, unfortunately)
private MainActivity sParent;
private WtfArrayFilter sFilter;
private Filter pFilter;
The extended constructor (we need to implement only the one we’re actually calling):
- call the inherited constructor
- store away the parent’s mFilter
value
- instantiate our own WtfArrayFilter
- store away the pre-filter normalisation method’s object, as WtfArrayFilter
will need it later
public WtfArrayAdapter(Context context, @LayoutRes int resource,
@NonNull T[] objects, MainActivity parent) {
super(context, resource, 0, Arrays.asList(objects));
sParent = parent;
sFilter = new WtfArrayFilter();
pFilter = super.getFilter();
}
Override ArrayAdapter
’s getFilter()
method to always return our new WtfArrayFilter
:
public Filter getFilter() {
return sFilter;
}
Implementation of WtfArrayFilter
as Filter
subclass just like ArrayFilter
does, and forwarding all boring (i.e. unchanged) calls to the inherited ArrayFilter
:
private class WtfArrayFilter extends Filter {
protected void publishResults(CharSequence constraint,
FilterResults results) {
pFilter.publishResults(constraint, results);
}
We only need to change one method to do our own filtering before calling the inherited ArrayFilter
’s filtering method:
protected FilterResults performFiltering(CharSequence prefix) {
return pFilter.performFiltering(prefix == null ? null :
sParent.normaliseAcronym(prefix.toString()));
}
}
}
Improvements welcome, I’m still a Java™ beginner.
Upvotes: 0
Reputation: 1121
ArrayList<YourModel> listFromActivity= null;
ArrayList<YourModel> mainList;
public MyConstructor(Context context, ArrayList<YourModel> listFromActivity) {
this.context = context;
this.listFromActivity= listFromActivity;
mainList= new ArrayList<>();
mainList.addAll(listFromActivity);
}
public void filter(String charText) {
charText = charText.toLowerCase(Locale.getDefault());
mainList.clear();
if (charText.length() == 0) {
mainList.addAll(arraylist);
} else {
for (YourObject wp : arraylist) {
if (wp.getName().toLowerCase(Locale.getDefault()).contains(charText) ||
wp.getKey().contains(charText)) {
mainList.add(wp);
}
}
}
notifyDataSetChanged();
}
and in activity or fragment when you use this adapter
edittext.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
String text = mSearch.getText().toString().toLowerCase(Locale.getDefault());
adaper.filter(text);
}
});
Upvotes: 0