Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to filter a ListView with runQueryOnBackgroundThread but nothing happens - what am I missing?

I have a list of countries in a database. I have created a select country activity that consists of a edit box for filtering and a list which displays the flag and country name.

When the activity starts the list shows the entire list of countries sorted alphabetically - works fine. When the customer starts typing into the search box I want the list to be filtered based on their typing. My database query was previously working in an AutoCompleteView (I just want to switch to a separate text box and list) so I know my full query and my constraint query are working. What I did was add a TextWatcher to the EditText view and every time the text is changed I invoke the list's SimpleCursorAdapter runQueryOnBackgroundThread with the edit boxes text as the constraint. The trouble is the list is never updated. I have set breakpoints in the debugger and the TextWatcher does make the call to runQueryOnBackgroundThread and my FilterQueryProvider is called with the expected constraint. The database query goes fine and the cursor is returned.

The cursor adapter has a filter query provider set (and a view binder to display the flag):

    SimpleCursorAdapter adapter = new SimpleCursorAdapter (this,
            R.layout.country_list_row, countryCursor, from, to);
    adapter.setFilterQueryProvider (new CountryFilterProvider ());
    adapter.setViewBinder (new FlagViewBinder ());

The FitlerQueryProvider:

private final class CountryFilterProvider implements FilterQueryProvider {

    @Override
    public Cursor runQuery (CharSequence constraint) {
        Cursor countryCursor = myDbHelper.getCountryList (constraint);
        startManagingCursor (countryCursor);
        return countryCursor;
    }
}

And the EditText has a TextWatcher:

    myCountrySearchText = (EditText)findViewById (R.id.entry);
    myCountrySearchText.setHint (R.string.country_hint);
    myCountrySearchText.addTextChangedListener (new TextWatcher() {
        @Override
        public void afterTextChanged (Editable s) {
            SimpleCursorAdapter filterAdapter = (SimpleCursorAdapter)myCountryList.getAdapter ();
            filterAdapter.runQueryOnBackgroundThread (s.toString ());
        }


        @Override
        public void onTextChanged (CharSequence s, int start, int before, int count) {
            // no work to do
        }


        @Override
        public void beforeTextChanged (CharSequence s, int start, int count, int after) {
            // no work to do
        }
    });

The query for the database looks like this:

public Cursor getCountryList (CharSequence constraint)  {
    if (constraint == null  ||  constraint.length () == 0)  {
        //  Return the full list of countries
        return myDataBase.query (DATABASE_COUNTRY_TABLE, 
                new String[] { KEY_ROWID, KEY_COUNTRYNAME, KEY_COUNTRYCODE }, null, null, null, 
                null, KEY_COUNTRYNAME);
    }  else  {
        //  Return a list of countries who's name contains the passed in constraint
        return myDataBase.query (DATABASE_COUNTRY_TABLE, 
                new String[] { KEY_ROWID, KEY_COUNTRYNAME, KEY_COUNTRYCODE }, 
                "Country like '%" + constraint.toString () + "%'", null, null, null, 
                "CASE WHEN Country like '" + constraint.toString () + 
                "%' THEN 0 ELSE 1 END, Country");
    }
}

It just seems like there is a missing link somewhere. Any help would be appreciated.

Thanks,

Ian

like image 343
Ian Leslie Avatar asked Dec 31 '10 17:12

Ian Leslie


1 Answers

I saw that you managed to solve your problem in another way, but thought I should add the answer for other people stumbling upon this question.

runQueryOnBackgroundThread() is only responsible for running a query for a constraint and returning a Cursor. To be able to filter the adapter based on the cursor you need to do something like

filterAdapter.getFilter().filter(s.toString());

A CursorAdapter always implements Filterable by default, and anything that implements filterable can be filtered using

getFilter().filter(constraint)

The way that the CursorAdapters built in filter works is that if you either override runQueryOnBackgroundThread() or if you use setFilterQueryProvider() then it runs that code in a background thread, gets a new cursor and sets it as the cursor of the CursorAdapter.

like image 140
dnaq Avatar answered Sep 28 '22 08:09

dnaq