5

As the title, how can I remove the filtering on an ArrayAdapter used by an AutoCompleteTextView to get the original list back?

A little more background:

It all started from the sad fact that the "position" value passed in to onItemClick() is useless. The "position" refers to the position AFTER the array has been filtered, but I need to know its REAL position. So, what I'm trying to do is when I've got the text of the selected item (by using getItemAtPosition(position)), I compare it one-by-one with the original string array that backs the ArrayAdapter. However, I found that when onItemClick() is called, the adapter is already filtered, I no longer have access to the original array. So I thought if I can remove the filter, maybe I can get back the original array and look for the selected item in it.

ArrayAdapter<String> mAdapter;

public void onCreate() {

    // Create an adapter and remembere it as a class member.
    mAdapter = new ArrayAdapter<String>(this, layoutId);

    // Add 100 strings to it and attach it to an AutoCompleteTextView
    for (int i = 0; i < 100; i++)
        mAdapter.add("random text");
    ((AutoCompleteTextView)findViewById(id)).setAdapter(mAdapter);
}

@Override
public void onItemClick(AdapterView<?> actv, View view, int position, long id) {

    if (actv.getAdapter().equals(mAdapter))
        Log.d("The adapter contained in actv is the same one I created earlier.");

    // And, I can get the text of the item the user selected

    String selected = (String)actv.getItemAtPosition(position);

    // However, although the adapter passed in is still the same one, but the  
    // number of items in it is only 1! Because the array has been filtered.

    int numItems = actv.getAdapter.getCount();

    // So, I'm thinking if I can somehow remove the filtering here, then I can
    // get back those 100 items, and do a search like following:

    for (int i = 0; i < actv.getAdapter.getCount(); i++)
       if (selected == actv.getAdapter.getItem(i))
            break;    // Eureka!!!
}

To tackle the problem of obtaining the REAL position of the selected item:

  1. Is there a way to utilize the "id" value? Like, assign each item an id, then hopefully onItemClick() would pass back the correct id.

  2. Like I said above, remove the filter (is it possible), get back the original 100 items, and perform a one-by-one search.

  3. This is the last resort, I know it'll work, but I don't want to do it: Once I get the text of the selected text, I go back to the source of the data (from a database), query those 100 items out, and perform the search.

  4. Another lame last resort: To avoid the overhead on accessing the database again as in #3, when in onCreate(), while creating the ArrayAdapter, I use an ArrayList of my own to remember all those 100 strings.

Am I doing it all wrong? What's the "right" way of obtaining the real position of the selected item from an AutoCompleteTextView?

Thank you very much!

(I read somewhere, some buy that seemed to be from Google Android team, said that one should use getFirstVisiblePosition() to resolve the position. But I can't figure out how.)

wwyt
  • 2,701
  • 4
  • 32
  • 42
  • I am doing something similiar HERE!!! http://stackoverflow.com/questions/12854336/autocompletetextview-backed-by-cursorloader – Etienne Lawlor Oct 30 '12 at 19:47

4 Answers4

2

I don't know if you're still interested, but I found this answering a similar question: Problem with AutoCompleteTextView and Spinner using the same Adapter

Copying the method in the AutoCompleteTextView source code:

Filter filter = mAdapter.getFilter();
filter = null;

See my response in the above question for the grepcode link.

Community
  • 1
  • 1
Aleadam
  • 40,203
  • 9
  • 86
  • 108
1

This is actually pretty simple to solve.. Instead of adding each element to the adapter as you get it (I'm assuming your random text part is just for example purposes), instead use the following:

First build your array into a variable, call it myArray.. then initialize your adapter like this:

mAdapter = new ArrayAdapter<String>(this, layoutId, myArray);

Now make sure that myArray is a class variable so you can reference it from anywhere else in the class.. Of course if you need access to this from another class you'd want to make a getter for it... Then you can easily iterate over the array to see if the value selected is in the array.. You'll have the whole set of data there instead of trying to get it from the adapter.

Here is a good example on using a validator for a similar looking use case: Android, Autocomplettextview, force text to be from the entry list

Community
  • 1
  • 1
Matt Wolfe
  • 8,924
  • 8
  • 60
  • 77
  • I think i spoke a bit too soon.. I'm confused why you would add each element to the adapter (which internally creates its own data structure, but you're averse to creating your own datastructure to store the data)... If you are really worried about resources you should be using a CursorAdaptor if the data is coming from a database.. Also note that in the example I sent you the array is sorted and you can do a binary search to check if the value is in the array -- O(log n) instead of O(n). – Matt Wolfe May 05 '11 at 05:16
0

In my case, I have address that can be set either by autocomplete or clicking on the map. If user click on the map, editText text should be set to address selected from the map, and in that case filtering should be disable temporarily.

I code like this:

public void OnAddressFound(String address) {
                // Temporary disable autocomplete
                editTextSearch.setAdapter(null);
                editTextSearch.setText(address);
                // Enable autocomplete again
                setAutoCompleteAdapter();
            }

where setAutoCompleteAdapter() is called during onCreate, and again in temporary disable/enable filter:

void setAutoCompleteAdapter() {
    PlacesAutoCompleteAdapter adapter = new PlacesAutoCompleteAdapter(this, R.layout.item_autocomplete_map_search, autoCompleteList);
    editTextSearch.setAdapter(adapter);
    adapter.notifyDataSetChanged();
}

Hope its help you also.

ivan.panasiuk
  • 1,239
  • 16
  • 20
0

I found the solution, kinnda tricky but its works

after i looking inside of the source, i found that th treshold variable used as filtering validation, here we just need to set the treshold to maximum int so filtering never perform.

threshold = Integer.MAX_VALUE

or

setThreshold(Integer.MAX_VALUE)