5

I implemented an AutoCompleteTextView where the data is updated from the server every time the user enters a new text input. It works well. However, every time I enter a new query, the previous results are displayed until the new result set is updated.

My guess is that it displays the currently queried results until the backend responds with the new search results. Is there a way to clear the current results?

Activity code:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_search_test);

    actv = (AutoCompleteTextView) findViewById(R.id.actv);
    actv.setThreshold(1);
    actv.setAdapter(new SearchSuggestionsAdapter(this, actv.getText().toString()));

Custom adapter:

public class SearchSuggestionsAdapter extends ArrayAdapter<String> {

    List<String> types = new ArrayList<>();
    protected static final String TAG = "SuggestionAdapter";
    private List<String> suggestions;
    private Context context;

    public SearchSuggestionsAdapter(Activity context, String nameFilter) {
        super(context, android.R.layout.simple_dropdown_item_1line);
        suggestions = new ArrayList<String>();
        this.context = context;
    }

    @Override
    public int getCount() {
        return suggestions.size();
    }

    @Override
    public String getItem(int index) {
        return suggestions.get(index);
    }

    @Override
    public Filter getFilter() {
        Filter myFilter = new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults filterResults = new FilterResults();

                if (constraint != null) {

                    //Get new results from backend
                    //searchItemsFromServer is the method that returns the data
                    //new data is successfully sent. no problem there
                    List<String> new_suggestions = searchItemsFromServer(constraint.toString());
                    suggestions.clear();
                    for (int i = 0; i < new_suggestions.size(); i++) {
                        suggestions.add(new_suggestions.get(i));
                    }

                    filterResults.values = suggestions;
                    filterResults.count = suggestions.size();
                }
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence contraint,
                                          FilterResults results) {
                if (results != null && results.count > 0) {
                    notifyDataSetChanged();
                } else {
                    notifyDataSetInvalidated();
                }
            }
        };
        return myFilter;
    }
}

Thank you in advance!

Jay
  • 4,873
  • 7
  • 72
  • 137
  • Clear adapter old values – Jitendra Singh Jul 24 '17 at 09:32
  • You have to cear your adapter and list old values as soon as your autocomplete text view value is empty or "". Add a Textwatcher in your autocompletetextview. then autoCompleteTextView.addTextChangedListener and onTextchanged method compare with empty value and clear – Kapil G Jul 24 '17 at 09:34
  • I tried that with `adapter.clear()`. No change. Is that what you mean? @kapsym – Jay Jul 24 '17 at 09:35
  • So you already added a textwatcher for it to determine when to clear it? – Kapil G Jul 24 '17 at 09:38
  • @kapsym I tried that out before by adding a text watcher in the activity after setting the adapter. Can you show me your implementation suggestion? – Jay Jul 24 '17 at 09:39
  • do not add any `TextWatcher` the way you are doing now is ok, you only need to use a different `List` inside your `Filter` - see how it is done in `ArrayAdapter`: `final ArrayList newValues = new ArrayList<>(` – pskink Jul 24 '17 at 09:39
  • @pskink Can you point out the change in relation to my code please? – Jay Jul 24 '17 at 09:41
  • @RickGrimesTheCoder did you call notifyDataSetChanged() after clear() ? – andrei Jul 24 '17 at 09:43
  • @andrei No I didn't – Jay Jul 24 '17 at 09:43
  • btw making a custom `Filter`s is a dirty job with no fun - see how easily you can do that with `FilterQueryProvider`: https://stackoverflow.com/a/19860624/2252830 – pskink Jul 24 '17 at 09:44
  • @pskink In that link you provided, what is `from` and `to` in the line: ` SimpleCursorAdapter a = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, null, from, to, 0);` – Jay Jul 24 '17 at 09:54
  • Can you add that as an answer in relation to my code please? @pskink – Jay Jul 24 '17 at 09:54
  • run this code, then make it simpler - by removing the second `TextView` - i assume you are using just one `TextView` in your adapter – pskink Jul 24 '17 at 09:58
  • @pskink Haha sorry I am confused. Not sure what you mean – Jay Jul 24 '17 at 10:00
  • did you run it? does it work? if so, just implement *your* `runQuery` method - this is the place where you call your web API – pskink Jul 24 '17 at 10:01
  • What's `from` and `to` in `SimpleCursorAdapter` in relation to my implementation? @pskink – Jay Jul 24 '17 at 10:03
  • from = {"suggestion"}; to = {android.R.id.text1}; – pskink Jul 24 '17 at 10:03
  • and: String[] columnNames = { BaseColumns._ID, "suggestion" }; – pskink Jul 24 '17 at 10:06
  • I don't have anything named `suggestion`. Do you mean the list named `suggestions`? @pskink – Jay Jul 24 '17 at 10:07
  • this is a column name - name it foo, bar, suggestion, whatewver - did you run that code? – pskink Jul 24 '17 at 10:08
  • Yep, same output. No change @pskink – Jay Jul 24 '17 at 10:38
  • try actv.setAdapter(null); right before actv.setAdapter(new SearchSuggestionsAdapter(this, actv.getText().toString())); – CCT May 10 '19 at 17:08

3 Answers3

3

Change your code to your activity to this

SearchSuggestionsAdapter searchSuggestionsAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_search_test);

    searchSuggestionsAdapter = new SearchSuggestionsAdapter(this, actv.getText().toString());
    actv = (AutoCompleteTextView) findViewById(R.id.actv);
    actv.setThreshold(1);
    actv.setAdapter(searchSuggestionsAdapter);
    actv.setOnFocusChangeListener(new OnFocusChangeListener() {

        @Override
        public void onFocusChange(View v, boolean hasFocus) {

            if(!hasFocus){
              searchSuggestionsAdapter.clear();
            }
        }
    });
}

Add the following code to your SearchSuggestionsAdapter

/**
 * Create list and notify recycler view
 */
public void clear() {
    if (suggestions != null) {
        suggestions.clear();
        notifyDataSetChanged();
    }
}
halfer
  • 19,824
  • 17
  • 99
  • 186
Karthik
  • 1,088
  • 6
  • 17
0
 actv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                suggestionAdapter.clear;
            }
        });

When user click on autocomplete remove the old adapter. But for this you need to define suggesstionAdapter first. and every time update this adapter and set it to autocomplete

FnR
  • 75
  • 1
  • 5
  • What if the user clicks on it once to get focus and then doesn't click again? This would only be limited to a click – Jay Jul 24 '17 at 09:45
  • So maybe using act.setOnFocusChangeListener instead of onClickListener ? – FnR Jul 24 '17 at 09:47
  • I actually tried this with a text watcher. So every time a new character is entered, the adapter is cleared. The issue persists. Thanks for the suggestion though – Jay Jul 24 '17 at 09:48
  • In your textwatcher onTextChanged method just check if your string is empty before firing clear otherwise dont clear as it would be a part of continued search – Kapil G Jul 24 '17 at 10:06
0

Clear suggestion before filtering. Call adapter.clear();

Add new method in adapter

public void clear() {
        suggestions.clear();
        notifyDataSetChanged();
    }
Pratik Popat
  • 2,891
  • 20
  • 31