Триггеры замены фрагментов 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}
Как я могу предотвратить очистку системы поиска при навигации?
Спасибо.
Ответы
Ответ 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
}
})