AutoCompleteTextView is a nice widget Android provides. It helps the user enter text by presenting him possible selections based on what he has entered so far.

Nicolas Klein has written a nice introduction of AutoCompleteTextView.
As a short recap: You have to provide a ListAdapter that also must implement the Filterable interface. The filterable adapter is used to define which proposals the Widget will display.
Everything is fine with an AutoCompleteTextView
if you set the adapter and only the user enters some text and selects the proposal he is looking for.
But it get's complicated if you want to set the value programmatically. Setting it in your code causes the dropdown to appear - though that's not what anyone would want in this case. At least that was not what was needed in a project I'm working on.
But nevermind, the widget has the method dismissDropDown()
. Surely this can be used to - well - dismiss the dropdown. Or to be more precise to stop it from appearing in the first place.
But no, that's not what's happening. Instead the popup gets displayed as if I hadn't called dismissDropdown()
. But why?
What actually happens is that the setText(CharSequence)
method causes some asynchronous methods to start: Whenever the text changes, the filter of the Adapter
is used to filter for possible proposals to show. And since the filter can take a long time, it is called asynchronously. Some time later the filter returns and its results get displayed when the UI thread gets processing time again. At this point in time the dismissDropDown()
method has long been completed - which is why this method has no effect whatsoever.
Annoying is, that there is a method in the AutoCompleteTextView
's source that does exactly what we want:
public void setText(CharSequence text, boolean filter)
With the second boolean parameter you can decide whether any filtering should happen - and without filtering no dropdown would pop up.
Alas it is hidden and we cannot use it as of now. This method is waiting for "API council approval". When and if this gets approved I do not know. If you do not have the Android code available you can have a look at the source on GrepCode.
But if you look at the code of AutoCompleteTextView
you can see a possible solution anyway. In the doAfterTextChanged()
method of the internal TextWatcher object we see this fragment:
if (mFilter != null) {
mPopupCanBeUpdated = true;
performFiltering(getText(), mLastKeyCode);
}
The performFiltering()
method is what starts the asynchronous filtering process so if this method isn't called all is nice and well.
The attribute mFilter
on the other hand gets set in AutoCompleteTextView
's setAdapter()
method:
if (mAdapter != null) {
//noinspection unchecked
mFilter = ((Filterable) mAdapter).getFilter();
adapter.registerDataSetObserver(mObserver);
} else {
mFilter = null;
}
So the solution is to set the adapter to null
before setting the text and directly afterwards setting it again to its old value.
Phew! This all took way too much time! But now it works. And in the end that's all that counts.