Grokking Android

Getting Down to the Nitty Gritty of Android Development

How Android’s AutoCompleteTextView Nearly Drove me Nuts

By

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.

AutoCompleteTextView showing its dropdown
AutoCompleteTextView showing its dropdown

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.

Wolfram Rittmeyer lives in Germany and has been developing with Java for many years.

He has been interested in Android for quite a while and has been blogging about all kind of topics around Android.

You can find him on Google+ and Twitter.