Converting an ArrayAdapter to CursorAdapter for use in a SearchView
D

2

22

How can I convert an ArrayAdapter<String> of static data into a CursorAdapter for using Suggestion Listener in SearchView? I have constructed the ArrayAdapter<String> from static data (allString)

ArrayAdapter<String> searchAdapter = new ArrayAdapter<String>(context, R.layout.listitem, allString);

and I use it for an MultiAutoCompleteTextView which works fine in devices with API level less than 11

MultiAutoCompleteTextView findTextView.setAdapter(searchAdapter);

However my target API is level is 11 and for API>10 I use an ActionBar within which I would like to have a SearchView instead.

Here's what I have tried: It does show the ActionBar with the embedded SearchView but does not give any suggestions as it would in the MultiAutoCompleteTextView.

@Override
public boolean onCreateOptionsMenu(Menu menu) {     
        MenuInflater inflater = getMenuInflater();

         if (android.os.Build.VERSION.SDK_INT > 10){
             inflater.inflate(R.menu.menu11, menu);
             searchView = (SearchView) menu.findItem(R.id.MENU_SEARCH).getActionView();
             int[] to = {0};
             CursorAdapter cursorAdapter = new SimpleCursorAdapter(context, R.layout.listitem, null, allBusStopString, to);
             searchView.setSuggestionsAdapter(cursorAdapter);
             searchView.setOnSuggestionListener(new OnSuggestionListener() {

                @Override
                public boolean onSuggestionClick(int position) {
                    String selectedItem = (String)cursorAdapter.getItem(position);
                    Log.v("search view", selectedItem);
                    return false;
                }

                @Override
                public boolean onSuggestionSelect(int position) {
                    return false;
                }
             });  
         }else{
             inflater.inflate(R.menu.menu, menu);
         }

    return true;
}
Doublure answered 24/7, 2012 at 9:43 Comment(0)
T
30

That's strange SearchView.setSuggestionsAdapter accepts CursorAdapter only.

You could create MatrixCursor and fill it with data from String array. I hope you have small data collection.

Then pass the cursor to CursorAdapter.

String[] columnNames = {"_id","text"}
MatrixCursor cursor = new MatrixCursor(columnNames);
String[] array = getResources().getStringArray(R.array.allStrings); //if strings are in resources
String[] temp = new String[2];
int id = 0;
for(String item : array){
    temp[0] = Integer.toString(id++);
        temp[1] = item;
    cursor.addRow(temp);
}               
String[] from = {"text"}; 
int[] to = {R.id.name_entry};
busStopCursorAdapter = new SimpleCursorAdapter(context, R.layout.listentry, cursor, from, to);
Thyrse answered 24/7, 2012 at 10:4 Comment(10)
I just had to add _id column to avoid the error explained hereDoublure
Yes indeed, I forgot about _idThyrse
The searchView seems to work fine but the Suggestions are wrong. it always shows all of the string entries, no matter what I type in search box. Aren't suggestions supposed to work like AutocompleteTextView or am I missing somthing?Doublure
I think you have to set OnQueryTextListener, recreate the cursor in this listener and change the cursor in adapter.Thyrse
yes, I did the OnQueryTextListener with my own autocomplete method and it works now. thanksDoublure
@BehzadMomahedHeravi: I am doing same thing but dont know how to do it with my Custom Content Provider. I want to filter Songs available in My Device. can you please help me for that?Endow
Nice One. I got Solution of what i want.Endow
how to filter the results on text change?Apportion
This should have not been the accepted answer. So for the newcomers i would strictly advice to look at the @kosiara - Bartosz Kosarzycki's answer below.Basipetal
what is R.id.name_entry ? @ThyrseSubaquatic
J
17

I was facing similar problem. You can use SearchView.setSuggestionsAdapter() which only accepts CursorAdapter. On the other hand... what's the point? If you use the standard <android.support.v7.widget.SearchView /> then it contains SearchAutoComplete which extends AppCompatAutoCompleteTextView inside. The following code worked for me:

List<String> items = Lists.newArrayList(new String[] {"aaaaa", "bbbbb", "ccccc", "ddddd"});
SearchView searchView = (SearchView) findViewById(R.id.autocomplete_searchview);
SearchView.SearchAutoComplete searchSrcTextView = (SearchView.SearchAutoComplete) findViewById(android.support.v7.appcompat.R.id.search_src_text);
searchSrcTextView.setThreshold(1);
searchSrcTextView.setAdapter(new SuggestionAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, items));
searchSrcTextView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        return;
    }
});

and the following Adapter code:

public class SuggestionAdapter<T> extends ArrayAdapter<T> {

    private List<T> items;
    private List<T> filteredItems;
    private ArrayFilter mFilter;

    public SuggestionAdapter(Context context, @LayoutRes int resource, @NonNull List<T> objects) {
        super(context, resource, Lists.<T>newArrayList());
        this.items = objects;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public T getItem(int position) {
        return items.get(position);
    }

    @Override
    public Filter getFilter() {
        if (mFilter == null) {
            mFilter = new ArrayFilter();
        }
        return mFilter;
    }

    public int getCount() {
        //todo: change to pattern-size
        return items.size();
    }

    private class ArrayFilter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence prefix) {
            FilterResults results = new FilterResults();

            //custom-filtering of results
            results.values = items;
            results.count = items.size();

            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            filteredItems = (List<T>) results.values;
            if (results.count > 0) {
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }
    }
}
Jeanejeanelle answered 14/12, 2015 at 18:0 Comment(3)
This returns everything no matter what you typeWaylen
This is the best solution if you haven't got a real cursor (fill a cursor 'manually' is a bad patch). It's working for me now, but I needed to change some of the example code: - Make findViewById for the searchAutoComplete like searchView.findViewById - Override getItems and getCounts of the adapter, use filteredItems instead items - It's obvious that you need to implement your filter logic, like the comment '//custom-filtering of results' saids. Thanks a lot for the example code!Erhard
This is perfect Im working with an elastic search endpoint I will just fetch the data and reset the adapter when I get new search results.Harwill

© 2022 - 2024 — McMap. All rights reserved.