How Android’s AutoCompleteTextView Nearly Drove me Nuts

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.

Share this article:

You can leave a response, or trackback from your own site.

5 Responses to “How Android’s AutoCompleteTextView Nearly Drove me Nuts”

  1. Bernard says:

    Thanks for sharing your solution! It would be worthwhile to raise the root cause of this as a bug with google. Android fires an event when program code sets/updats the model of a TextView. This is is NOT an event! An event should only ever be fired when the user changes the model. See http://code.google.com/p/android/issues/detail?id=27653

    • Sorry, for being that late. Had a lot on my mind recently.

      I am not sure if this is a bug. The text actually changes and thus all listeners should be called. Their TextWatcher implementation is just one listener.

      What should happen though, is that the alternative method should be approved as quickly as possible by this API council (whoever they are).

      I have filed a feature request to publish this method as soon as possible:
      http://code.google.com/p/android/issues/detail?id=34690

  2. Rahul Narkhede says:

    Couldn’t you use replaceText() method in AutoCompleteTextView? I had a similar task where I was using a complex object and view in the adapter of MultiAutoCompleteTextView. The end user had a feature to select the object from a list of objects appearing in suggestion pop-up below also by launching a separate selection screen for the objects.
    Once the objects were selected from the other activity, I populated the text in my MultiAutoCompleteTextview by sending each object’s display text to replaceText() method and all worked as expected. Please let me know in case you think, there is something I missed here.

  3. Rahul Narkhede says:

    Oh, yes replaceText is protected Method. Since I was trying to use MultiAutoCompleteTextView for creating chips like in MessagingApp, I could use this method

Leave a Reply

You can also subscribe without commenting.

Subscribe to RSS Feed My G+-Profile Follow me on Twitter!