dschulten dschulten - 6 months ago 162
Android Question

Is there a better way to restore SearchView state?

I have a collapsible

SearchView
in my
ActionBar
. After a search has been performed, the associated
ListView
is filtered to show only matching items. During that state, the
SearchView
is still expanded and shows the search string. If the user closes the
SearchView
, I remove the filter.

I want to restore the search state, e.g. on configuration change or if the activity was destroyed when I return to it from another activity.

I restore the query string in
onRestoreInstanceState()
, and if I find a query string in
onCreateOptionsMenu()
I call

searchView.setQuery(query, true);


so as to execute the query again. It turned out that this is better than applying the query filter immediately
onRestoreInstanceState()
. With the latter the list is shortly shown unfiltered, only then the query is applied again. With
setQuery()
this does not happen.

Problem: The query is executed and the list is filtered, but the search view remains collapsed. Therefore the user cannot use the search view to remove the filter or to apply another query.

In
onCreateOptionsMenu()
I can be sure that the search item and the search view exists, therefore I can call
searchItem.expandActionView()
. Strangely, only this really expands the
ActionView
- calling
setIconified(false)
does not expand the view, not even when it is called twice in a row.

If I use
expandActionView()
before I call
setQuery()
, the
SearchView
is opened and shows the text (otherwise
expandActionView()
empties the
SearchView
).

Unfortunately,
expandActionView()
has a side effect: the suggestion list is also shown and the keyboard opens.

I can hide the keyboard using
searchView.clearFocus()
. So the remaining problem is the suggestion list. How can I close an open suggestion list on a
SearchView
that has text?

I wonder if there is a better way to restore a search view in the action bar that does not have so many side effects.

Answer

I have found a workaround. It is extremely ugly, but it works.

So here is how I was able to restore the search box instance state after a configuration change.

First of all, restore the query string in onRestoreInstanceState

currentQuery = state.getString(KEY_SAVED_FILTER_CONSTRAINT);

In onCreateOptionsMenu set up the search view and if there is a currentQuery, expand the search item and submit the query again. Clear the focus to hide the keyboard.

    MenuItem searchItem = menu.findItem(R.id.action_search);
    searchView = (SearchView) searchItem.getActionView();
    searchView.setSearchableInfo(searchManager
            .getSearchableInfo(getComponentName()));

    if (!TextUtils.isEmpty(currentQuery)) {
        searchItem.expandActionView();
        searchView.setQuery(currentQuery, true);
        searchView.clearFocus();
    }

Finally we need to close the suggestion list. Here is how to get the query text view from the search view:

private AutoCompleteTextView findQueryTextView(ViewGroup viewGroup) {
    AutoCompleteTextView queryTextView = null;
    if (viewGroup != null) {
        int childCount = viewGroup.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = viewGroup.getChildAt(i);
            if (child instanceof AutoCompleteTextView) {
                queryTextView = (AutoCompleteTextView) child;
                break;
            } else if (child instanceof ViewGroup) {
                queryTextView = findQueryTextView((ViewGroup) child);
                if (queryTextView != null) {
                    break;
                }
            }
        }
    }
    return queryTextView;
} 

Then you can dismiss the suggestion list:

    AutoCompleteTextView queryTextView = findQueryTextView(searchView);
    if (queryTextView != null) {
        queryTextView.dismissDropDown();
    }

This does however not work from within onCreateOptionsMenu. I had to move the invocation of dismissDropDown into the onNewIntent method of my activity to make it work.

What makes this so ugly is the fact that the restoration steps are dispersed over various phases of the lifecycle and that a recursive view search is necessary to get to the suggestion list.

Comments