Ecker Bottini
Ecker Bottini

Reputation: 5

Listview autocomplete

I have a simple question:

I have a Listview Data with these strings:

String words[] = {
        "man",
        "guy",
        "penny-wise",
        "(just)",

I added a search funciontality to Listview, like this:

         * Enabling Search Filter
     * */
    search.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
            // When user changed the Text
            Words.this.adapter.getFilter().filter(cs); {

                lv.setOnItemClickListener(new OnItemClickListener(){

                    public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                    long arg3) {




                    }

                });

            }


        }

        @Override
        public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
                int arg3) {
            // TODO Auto-generated method stub

        }

        @Override
        public void afterTextChanged(Editable arg0) {
            // TODO Auto-generated method stub                          
        }




    });
}

So, the search functionality works well, but I want to this recognize when I am typing a part of the ceratin word from string (listview data) as "wise" from penny-wise item, they don't offer penny-wise as a suggestion that it should be (because it is exist in listview data)

If I type JUST they don't offer as suggestion... because there is a ( ) in my string...

How can I solve this. I am newbie. Thanks!!!

Upvotes: 0

Views: 557

Answers (1)

Ifrit
Ifrit

Reputation: 6821

You'll need to create your own custom filter for the adapter. In order to do this, you'll need to create your own custom adapter class. This is not exactly an easy task, especially considering you are a newbie.

You didn't mentioned what type of adapter you are using. If it's an ArrayAdapter, then your best and easiest solution is to use the Advanced-Adapters open-source library. It has an equivalent adapter which easily lets you customize the filtering logic, however you'll need to handle the view creation manually. You can read more about that here.

Otherwise, many people will tell you to just extend the ArrayAdapter class directly and override the getFilter() method however that's an incorrect answer. Why? Multiple reasons.

The filter operation occurs on a background thread. That means you need to worry about concurrency issues. This presents some problems. For one, the lock the ArrayAdapter uses isn't exposed, nor is the lock using the class instance. That means you'll need your own lock which greatly ups the risk of deadlocking...having two different locks for the same set of data is bad especially since the ArrayAdapter syncs in more places then just the filter.

The ArrayAdapter uses two Lists to track it's data: mObjects and mOriginalValues. The former tracks the displayed list, the latter tracks the entire list for when a filter operation occurs. For example, if you filter a list of 10 items to only show 1, internally the adapter still needs to know what the original 10 were for restoring the list later. When overriding just the getFilter() you must provide this similar behavior but there's one major problem. The ArrayAdapter does not expose either List. While you can pull items from mObjects one at a time, you can't pull the entire List itself. A common solution is to just create another List when instantiating your custom adapter with items.

However this presents further issues as there a multitude of ways to add/remove/update items in the adapter. Which means you need to override every mutate method to ensure your list stays in sync with the ArrayAdapter. Add the fact that you have to account for whether the adapter is further being filtered complicates the matter. Basically your list can easily get out of sync from the internal ArrayAdapter's.

By this point you are already overriding so many of the ArrayAdapter's methods, it makes the ArrayAdapter largely irrelevant. The moment you start tracking a list of data in a custom class derived from ArrayAdapter, is the moment you should stop and just implement your own adapter from scratch.

This is why creating your own adapter from the BaseAdapter is the best solution. If you know what your doing, it's not hard to do...just a pain really. Otherwise that open source library does all that for you while leaving the getView() method abstract and exposing a method to customize the filter logic.

Upvotes: 2

Related Questions