Подтвердить что ты не робот

Триггеры замены фрагментов onQueryTextChange при поиске

Вот как я перемещаюсь по своему приложению:

  • Открыть фрагмент со списком
  • Список фильтров по тексту, введенному в searchview
  • Нажмите на listitem (фрагмент списка заменяется фрагментом детали)
  • Переход назад (фрагмент детали заменяется фрагментом списка)

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

Проблема: Я не могу сохранить фактическое значение фильтра, потому что onQueryTextChange вызывается, когда я перемещаюсь из списка в детали, потому что что-то очистило текст searchview.

// ...
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String s) {
            return false;
        }

        @Override
        public boolean onQueryTextChange(String s) {
            searchReceived(s);
            return true;
        }
    });
// ...

public void searchReceived(String searchQuery)
{
    this.stateHolder.searchQuery = searchQuery;
    // more code...
}

Когда я хочу восстановить фильтр при навигации назад, он просто фильтрует пустую строку, потому что неправильное значение сохраняется в this.stateHolder.searchQuery.

Стек:

onQueryTextChange():139, EmployeeListFragment$1 {com.example.exampleapp.fragment}
onTextChanged():1153, SearchView {android.widget}
access$2000():92, SearchView {android.widget}
onTextChanged():1638, SearchView$11 {android.widget}
sendOnTextChanged():7408, TextView {android.widget}
setText():3816, TextView {android.widget}
setText():3671, TextView {android.widget}
setText():80, EditText {android.widget}
setText():3646, TextView {android.widget}
setQuery():511, SearchView {android.widget}
onActionViewCollapsed():1250, SearchView {android.widget}
collapseItemActionView():1662, ActionBarView$ExpandedActionViewMenuPresenter {com.android.internal.widget}
collapseItemActionView():1258, MenuBuilder {com.android.internal.view.menu}
clear():521, MenuBuilder {com.android.internal.view.menu}
doInvalidatePanelMenu():789, PhoneWindow {com.android.internal.policy.impl}
run():221, PhoneWindow$1 {com.android.internal.policy.impl}

Как я могу предотвратить очистку системы поиска при навигации?

Спасибо.

4b9b3361

Ответ 1

Через 2 дня Googling я получил решение, которое определенно поможет вам.

У меня есть только cut and pasted код от onCreateOptionMenu() до onPrepareOptionMenu()

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

@Override
public void onPrepareOptionsMenu(Menu menu) {
    super.onPrepareOptionsMenu(menu);
    getSherlockActivity().getSupportMenuInflater().inflate(R.menu.menu_all_order, menu);

    searchView = (SearchView) menu.findItem(R.id.menu_all_order_search).getActionView();
    searchView.setInputType(InputType.TYPE_CLASS_NUMBER);
    searchView.setQueryHint("Enter Order No");
    searchView.setOnQueryTextListener(this);
}

и удалить:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);
}

Спасибо:)

Ответ 2

Проблема заключается в том, что ActionBar (и подкомпоненты) сбрасываются, когда заменяющий его фрагмент заменяется. Когда это произойдет, запрос SearchView очищается, как показано в onActionViewCollapsed. Методы обхода:

Предотвращение сжимания

Удалите setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW); из кода создания searchview или android:showAsAction="collapseActionView" из его кода xml.

Это повлияет на то, как/когда кнопки просмотра закрытия/голоса будут отображаться при попытке свернуть его

Было бы также возможно предотвратить свертывание путем переопределения метода SearchView onActionViewCollapsed(), чтобы ничего не делать, но выполнил бы то же самое.

Игнорировать изменения запроса при необходимости

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

public boolean onQueryTextChange(String newText) {
    if (!isVisible()) {
        // The fragment was replaced so ignore
        return true;
    }
    // Text was actually changed, perform search
    return true;
}

Это будет лучший вариант, поскольку это не влияет на функциональность searchview.

Ответ 3

Я вижу, что вы еще не нашли решения, у меня есть такая же проблема здесь:

Я обнаружил, что при вызове invalidateOptionsMenu также вызывается метод onQueryTextChange, потому что View start dispatchRestoreInstanceState с предыдущим значением после того, как вы очистили поиск, например. Вы называете invalidateOptionsMenu возможно?

Возможно, внутри onQueryTextChange, вы можете проверить логическое значение в текущем состоянии объектов вашего приложения, чтобы узнать, должен ли быть выполнен контент метода. В моем случае я использую mDrawerLayout.isDrawerOpen(..), чтобы разрешить поиск.

Также вы можете реализовать SearchView.OnQueryTextListener для каждого класса, который вы используете, в Fragment или в классе основной деятельности, где-то в классе вы можете установить переменную модуля boolean, которую вы проверите внутри onQueryTextChange.

Ответ 4

Я изменил атрибут элемента меню showAsAction от android:showAsAction="always|collapseActionView" до android:showAsAction="always". Теперь внешний вид и поведение searchview немного изменились, но searchQuery не очищается!

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
            android:id="@+id/actionSearch"
            android:icon="@android:drawable/ic_menu_search"
            android:actionViewClass="android.widget.SearchView"
            android:showAsAction="always"
            android:title="@android:string/search_go"
    />
</menu>

Ответ 5

Это мое решение:

 @Override
        public boolean onQueryTextChange(final String newText) {

            if (searchTF.isIconified())
                return false;

            // put the "real" onQueryTextChange actions here


            return true;


        }

Ответ 6

Использование androidx.appcompat.widget.SearchView + LiveData + ViewModel:

searchView.setOnQueryTextListener(object: SearchView.OnQueryTextListener {
    override fun onQueryTextSubmit(query: String?): Boolean {
        viewModel.setSearchQuery(query)
        return true
    }
    override fun onQueryTextChange(newText: String?): Boolean {
        if(searchView.isIconified || !isVisible) {
            // Don't call setSearchQuery when SearchView is collapsing/collapsed
            return true
        }
        viewModel.setSearchQuery(newText)
        return true
    }
})

Ответ 7

Если у кого-то возникнет такая же проблема, обратный вызов onQueryTextChange будет запущен при замене фрагмента при использовании следующего действия в файле XML вашего меню, когда ваш SearchView в настоящее время расширен:

android:showAsAction="always|collapseActionView"

Когда вы пытаетесь использовать isVisible() (Java) или isVisible (Kotlin) в обратном вызове onQueryTextChange как способ определить, является ли фрагмент видимым или нет, возвращаемое значение всегда будет возвращать true.

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

Действие collapseActionView по умолчанию на этом этапе - свернуть SearchView при изменении фрагмента.

Решение:

Просто вызовите свой метод SearchView ! IsIconified (Kotlin) в обратном вызове onQueryTextChange и установите свою логику только в том случае, если он возвращает false, т.е. SearchView в настоящее время расширен. Полный пример описан ниже:

yourSearchView.setOnQueryTextListener(object: SearchView.OnQueryTextListener {
    override fun onQueryTextSubmit(query: String?): Boolean {
        // Do search query here if you use a submit action
        return true
    }

    override fun onQueryTextChange(newText: String?): Boolean {
        if (!yourSearchView.isIconified) {
            // Don't execute your search query here when SearchView is 
            // currently open
            return true
        }
        // Do search query here
        return true
    }
})