How to dynamically add suggestions to autocompletetextview with preserving character status
Asked Answered
L

2

14

Problem Description:

I am facing some problem with AutoCompleteTextView where I have to show suggestions after each keypress. Thing is that, list of suggestion is dynamic like google's suggestion feature. It means the new suggestions should be added as user keeps typing in plus all matching old suggestions should be displayed.

For example

I write "te" and then it should display previous suggestions like "test1" & "test2" and the new suggestions that I will get from Web API. Suppose web api gives me word "tea"& "tension ".

Now the AutoCompleteTextView will have "te" as string with all four suggestions showing below it.

This is exactly what I am looking for.

looks simple but it is showing a strange behaviour.

I am using default ArrayAdapter class instance of which I am declaring globally.

arrayAdapter=new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line,suggestions);
word.setAdapter(arrayAdapter);

suggestions is ArrayList.

Upon getting new result from WebApi I simply call

arrayAdapter.notifyDataSetChanged();

to refresh the data observer and views attached with this (in our case AutoCompleteListView).

But it closes suggestions.

When I don't use notifyDataSetChanged(); it is showing all suggestions regardless of characters I have typed.

I tried it with custom filter as many suggested but none of them is helpful as I couldn't use notifyDataSetChanged().

I am posting an image to avoid confusions.enter image description here

I have a confusion that why notifyDataSetChanged(); its not working. I haven't use any other reference of list with same arrayAdapter instance. I really doubt if it's a reference problem.

Lecky answered 8/11, 2013 at 12:12 Comment(6)
when and how do you add web results to the adapter?Shipload
@pskink:i add it in the suggestions which is ArrayList.then i call notifyDataSetChanged().i do this in postExecute() of Asynctask which fetches result from WebApi.Lecky
you should do that in performFilteting/publishResults methotds of your adapter's FilterShipload
i haven't tried that.Let me check for it.Lecky
or you can use existing Filters like CursorFilter and its integrarion with CursorAdapter, see my answer belowShipload
updated the answer by adding wikipedia free opensearchShipload
S
19

one of the easiest way of doing that (put the code in onCreate):

EDIT: addied wikipedia free opensearch (if https://en.wikipedia.org doesn't work try http://en.wikipedia.org)

    AutoCompleteTextView actv = new AutoCompleteTextView(this);
    actv.setThreshold(1);
    String[] from = { "name", "description" };
    int[] to = { android.R.id.text1, android.R.id.text2 };
    SimpleCursorAdapter a = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, null, from, to, 0);
    a.setStringConversionColumn(1);
    FilterQueryProvider provider = new FilterQueryProvider() {
        @Override
        public Cursor runQuery(CharSequence constraint) {
            // run in the background thread
            Log.d(TAG, "runQuery constraint: " + constraint);
            if (constraint == null) {
                return null;
            }
            String[] columnNames = { BaseColumns._ID, "name", "description" };
            MatrixCursor c = new MatrixCursor(columnNames);
            try {
                String urlString = "https://en.wikipedia.org/w/api.php?" +
                        "action=opensearch&search=" + constraint +
                        "&limit=8&namespace=0&format=json";
                URL url = new URL(urlString);
                InputStream stream = url.openStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
                String jsonStr = reader.readLine();
                // output ["query", ["n0", "n1", ..], ["d0", "d1", ..]]
                JSONArray json = new JSONArray(jsonStr);
                JSONArray names = json.getJSONArray(1);
                JSONArray descriptions = json.getJSONArray(2);
                for (int i = 0; i < names.length(); i++) {
                    c.newRow().add(i).add(names.getString(i)).add(descriptions.getString(i));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return c;
        }
    };
    a.setFilterQueryProvider(provider);
    actv.setAdapter(a);
    setContentView(actv, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
Shipload answered 8/11, 2013 at 13:49 Comment(6)
Hey, I got the solution,you was right about your comment.it helped me to partially solve the issue. Though i had some other issues too that i am currently working on. I didn't check this way to achieve the answer as i don't want to use database for this single purpose. I am thankful to you for your complete support and giving you upcount for this one. thanks for all your help.Lecky
i dont use any database, data is read from the json web serviceShipload
I tried so many different things so far: TextWatcher, AsyncTask, etc. This is exactly was I was looking for ! Best piece of code I could find. Works perfectly !Swoosh
@OlivierP. simple yet working, isn't it? unfortunately 90% of people here still want to fight with those watchers, custom ArrayAdapters, AsyncTasks etc even if they saw this so simple solution, i have no idea why...Shipload
@Shipload I was one of them ^^ I din't know this could be done this way. I'm glad I found your piece of code. Moreover when you search over Internet, StackOverflow, etc. your answer is not the highlighted one where it should definitely be !Swoosh
@OlivierP. you were one of them but you didnt see this solution before, i am talking about those guys who saw it but still believe that data stored in some POJO and ArrayAdapter is somehow "better" than data stored in a Cursor used by a CursorAdapterShipload
G
0

You have impletent the custome filter in the child class of ArrayAdapter, there in perform filter method you have to do network call and get data from server. You can set this data in your main arraylist.

Goblin answered 19/8, 2017 at 5:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.