Есть ли лучший способ восстановить состояние SearchView?

У меня есть складной SearchView в моем ActionBar. После того, как поиск выполнен, связанный ListView фильтруется, чтобы отображать только соответствующие элементы. Во время этого состояния SearchView все еще расширяется и отображает строку поиска. Если пользователь закрывает SearchView, я удаляю фильтр.

Я хочу восстановить состояние поиска, например. при изменении конфигурации или если действие было уничтожено, когда я возвращаюсь к нему из другого действия.

Я восстанавливаю строку запроса в onRestoreInstanceState(), и если я найду строку запроса в onCreateOptionsMenu(), я вызываю

searchView.setQuery(query, true); 

чтобы выполнить запрос еще раз. Оказалось, что это лучше, чем сразу применить фильтр запросов onRestoreInstanceState(). С последним список вкратце показан нефильтрованным, только тогда запрос снова применяется. С setQuery() этого не происходит.

Проблема: запрос выполняется, и список фильтруется, но окно поиска остается свернутым. Поэтому пользователь не может использовать представление поиска, чтобы удалить фильтр или применить другой запрос.

В onCreateOptionsMenu() я могу быть уверен, что элемент поиска и вид поиска существуют, поэтому я могу позвонить searchItem.expandActionView(). Как ни странно, только это действительно расширяет ActionView - вызов setIconified(false) не расширяет представление, даже если он вызывается дважды в строке.

Если я использую expandActionView(), прежде чем я вызову setQuery(), откроется SearchView и покажет текст (иначе expandActionView() пустет SearchView).

К сожалению, expandActionView() имеет побочный эффект: также отображается список предложений и открывается клавиатура.

Я могу скрыть клавиатуру, используя searchView.clearFocus(). Таким образом, оставшаяся проблема - список предложений. Как закрыть открытый список предложений на SearchView с текстом?

Интересно, есть ли лучший способ восстановить представление поиска в панели действий, в которой не так много побочных эффектов.

Ответ 1

Я нашел обходное решение. Это очень уродливо, но оно работает.

Итак, вот как мне удалось восстановить состояние экземпляра окна поиска после изменения конфигурации.

Прежде всего, восстановите строку запроса в onRestoreInstanceState

currentQuery = state.getString(KEY_SAVED_FILTER_CONSTRAINT);

В onCreateOptionsMenu настройте представление поиска, и если есть currentQuery, разверните элемент поиска и снова отправьте запрос. Снимите фокус, чтобы скрыть клавиатуру.

    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();
    }

Наконец, нам нужно закрыть список предложений. Вот как получить текстовый вид запроса из вида поиска:

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;
} 

Затем вы можете отклонить список предложений:

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

Однако это не работает изнутри onCreateOptionsMenu. Мне пришлось переместить вызов функции rejectDropDown в метод onNewIntent моей активности, чтобы он работал.

Что делает это настолько уродливым, так это то, что шаги восстановления разбросаны по различным этапам жизненного цикла и что для получения списка предложений необходим рекурсивный поиск в виде.

Ответ 2

По моему скромному мнению. Если вы хотите восстановить состояние searchView, мы должны использовать onSaveInstanceState (Bundle outState). Вызывается для извлечения состояния каждого экземпляра из активности перед тем, как его убить, чтобы состояние можно было восстановить в onCreate (Bundle) или onRestoreInstanceState (Bundle) ( Bundle, заполненный этим методом, будет передан обоим).

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // if you saved something on outState you can recover them here
    if (savedInstanceState != null) {
             mSearchString = savedInstanceState.getString(SEARCH_KEY);
    }
}

// This is called before the activity is destroyed
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    mSearchString = mSearchView.getQuery().toString();
    outState.putString(SEARCH_KEY, mSearchString);
}

Этот метод вызывается до того, как действие может быть убито, так что, когда он вернется через некоторое время в будущем, он сможет восстановить свое состояние. Теперь, когда пользователь меняет ориентацию, состояние пользовательского интерфейса может быть восстановлено через onCreate (Bundle) или onRestoreInstanceState (Bundle).

Теперь мы должны использовать onCreateOptionsMenu (меню меню), потому что нам нужно сфокусировать наш SearchView.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main, menu);

    MenuItem searchMenuItem = menu.findItem(R.id.menu_main_action_search);

    mSearchView = (SearchView) MenuItemCompat.getActionView(searchMenuItem);

    //focus the SearchView
    if (mSearchString != null && !mSearchString.isEmpty()) {
        searchMenuItem.expandActionView();
        mSearchView.setQuery(mSearchString, true);
        mSearchView.clearFocus();
    }

    return super.onCreateOptionsMenu(menu);
}

Также вы можете проверить эту ссылку с полным кодом.