如何在输入文本时防止 android SearchView 查询切换
How to prevent android SearchView Query toggling while text is typing
我通过 SearchView 组件获得了视图。问题是输入字段中的每个新符号都会切换 Query
操作,所以有一些 http
请求被触发等,所以它开始运行缓慢。
我希望它 运行 只有在我点击虚拟键盘上的搜索按钮(下面的按钮)之后。
SearchView
中是否有任何属性?
布局代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SearchView
android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
local:MvxBind="Query SearchString" />
</LinearLayout>
或者我应该做一些类似自定义绑定的东西来检测键盘按键点击?
更新:
一些代码可以清楚地说明搜索的部分工作原理:
查看模型
public class RemoteMusicSearchViewModel : MvxViewModel
{
private IMvxNavigationService _mvxNavigationService;
private IRemoteMusicDataService _remoteMusicDataService;
private int _currentPage;
public RemoteMusicSearchViewModel(IMvxNavigationService mvxNavigationService,
IRemoteMusicDataService remoteMusicDataService)
{
_mvxNavigationService = mvxNavigationService;
_remoteMusicDataService = remoteMusicDataService;
}
public override void Start()
{
base.Start();
_currentPage = 0;
}
private string _searchString;
public string SearchString
{
get { return _searchString; }
set
{
_searchString = value;
RaisePropertyChanged(() => SearchString);
PerformBasicSearch().ConfigureAwait(false);
}
}
private ObservableCollection<DownloadableEntity> _foundItems;
public ObservableCollection<DownloadableEntity> FoundItems
{
get { return _foundItems; }
set
{
if (_currentPage > 0)
{
_foundItems = new ObservableCollection<DownloadableEntity>(_foundItems.Concat(value));
}
else
{
_foundItems = value;
}
RaisePropertyChanged(() => FoundItems);
}
}
private async Task PerformBasicSearch(int page = 0)
{
string request = SearchString;
string result = await _remoteMusicDataService.SearchByProperty(request, MusicSearchType.ByTracks, page).ConfigureAwait(false);
var searchResult = MusicSearchResult.FromJson(result);
await PrepareDataForOutput(searchResult).ConfigureAwait(false);
}
}
完整布局代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SearchView
android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
local:MvxBind="Query SearchString"
/>
<MvvmCross.Binding.Droid.Views.MvxListView
android:id="@+id/searchlist"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
local:MvxBind="ItemsSource FoundItems"
local:MvxItemTemplate="@layout/listitem"/>
</LinearLayout>
我猜您正在寻找问题的手动解决方案。
例如,对于您获得的每个按键事件,您可以在某个阈值 500 毫秒后触发延迟操作。
也许使用 Handler.postDelayed()
然后就是三种情况
- 另一个事件在触发之前发生,因此您调用
Handler.removeCallbacks()
并触发另一个延迟操作
- 另一个事件在请求已经触发时出现,但还没有结果,因此您取消请求并触发延迟的操作。
- 事件发生时没有延迟操作挂起或请求挂起,因此您只需触发延迟操作。
但是,如果您愿意使用任何 Reactive 变体,则有更复杂的解决方案,基本上是消除键盘敲击事件。
我找到了解决方案 - 我刚刚为此创建了新的绑定:
public class SearchViewKeyPressEventsBinding : MvxAndroidTargetBinding
{
private readonly SearchView _searchView;
private IMvxAsyncCommand _command;
public SearchViewKeyPressEventsBinding(SearchView searchView) : base(searchView)
{
_searchView = searchView;
_searchView.QueryTextSubmit += _searchView_KeyPress;
}
private void _searchView_KeyPress(object sender, SearchView.QueryTextSubmitEventArgs e)
{
try
{
if (_command != null)
{
_command.ExecuteAsync();
}
}
catch (Exception ex)
{
throw ex;
}
}
public override Type TargetType
{
get { return typeof(IMvxAsyncCommand); }
}
protected override void SetValueImpl(object target, object value)
{
try
{
_command = (IMvxAsyncCommand)value;
}
catch (Exception e)
{
Log.Error("SOME BINDER FAIL\n\t" + e.Message + "\n", "SOME BINDER FAIL\n\t" + e.Message + "\n");
throw;
}
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
_searchView.QueryTextSubmit -= _searchView_KeyPress;
}
base.Dispose(isDisposing);
}
}
}
然后注册成功:
registry.RegisterFactory(new MvxCustomBindingFactory<SearchView>("OnSearchSubmit", (sv) => new SearchViewKeyPressEventsBinding(sv)))
布局中:
<SearchView
android:id="@+id/search10"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
local:MvxBind="Query SearchString; OnSearchSubmit OnSubmitPressCommand" />
并且不要忘记设置视图模型的 属性:
public IMvxAsyncCommand OnSubmitPressCommand
{
get
{
return new MvxAsyncCommand(OnSearchSubmit);
}
}
private async Task OnSearchSubmit()
{
//HideKeyboardOnSearchStart.Invoke(this, null);
await PerformBasicSearch().ConfigureAwait(false);
}
我通过 SearchView 组件获得了视图。问题是输入字段中的每个新符号都会切换 Query
操作,所以有一些 http
请求被触发等,所以它开始运行缓慢。
我希望它 运行 只有在我点击虚拟键盘上的搜索按钮(下面的按钮)之后。
SearchView
中是否有任何属性?
布局代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SearchView
android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
local:MvxBind="Query SearchString" />
</LinearLayout>
或者我应该做一些类似自定义绑定的东西来检测键盘按键点击?
更新:
一些代码可以清楚地说明搜索的部分工作原理:
查看模型
public class RemoteMusicSearchViewModel : MvxViewModel
{
private IMvxNavigationService _mvxNavigationService;
private IRemoteMusicDataService _remoteMusicDataService;
private int _currentPage;
public RemoteMusicSearchViewModel(IMvxNavigationService mvxNavigationService,
IRemoteMusicDataService remoteMusicDataService)
{
_mvxNavigationService = mvxNavigationService;
_remoteMusicDataService = remoteMusicDataService;
}
public override void Start()
{
base.Start();
_currentPage = 0;
}
private string _searchString;
public string SearchString
{
get { return _searchString; }
set
{
_searchString = value;
RaisePropertyChanged(() => SearchString);
PerformBasicSearch().ConfigureAwait(false);
}
}
private ObservableCollection<DownloadableEntity> _foundItems;
public ObservableCollection<DownloadableEntity> FoundItems
{
get { return _foundItems; }
set
{
if (_currentPage > 0)
{
_foundItems = new ObservableCollection<DownloadableEntity>(_foundItems.Concat(value));
}
else
{
_foundItems = value;
}
RaisePropertyChanged(() => FoundItems);
}
}
private async Task PerformBasicSearch(int page = 0)
{
string request = SearchString;
string result = await _remoteMusicDataService.SearchByProperty(request, MusicSearchType.ByTracks, page).ConfigureAwait(false);
var searchResult = MusicSearchResult.FromJson(result);
await PrepareDataForOutput(searchResult).ConfigureAwait(false);
}
}
完整布局代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SearchView
android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
local:MvxBind="Query SearchString"
/>
<MvvmCross.Binding.Droid.Views.MvxListView
android:id="@+id/searchlist"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
local:MvxBind="ItemsSource FoundItems"
local:MvxItemTemplate="@layout/listitem"/>
</LinearLayout>
我猜您正在寻找问题的手动解决方案。
例如,对于您获得的每个按键事件,您可以在某个阈值 500 毫秒后触发延迟操作。
也许使用 Handler.postDelayed()
然后就是三种情况
- 另一个事件在触发之前发生,因此您调用
Handler.removeCallbacks()
并触发另一个延迟操作 - 另一个事件在请求已经触发时出现,但还没有结果,因此您取消请求并触发延迟的操作。
- 事件发生时没有延迟操作挂起或请求挂起,因此您只需触发延迟操作。
但是,如果您愿意使用任何 Reactive 变体,则有更复杂的解决方案,基本上是消除键盘敲击事件。
我找到了解决方案 - 我刚刚为此创建了新的绑定:
public class SearchViewKeyPressEventsBinding : MvxAndroidTargetBinding
{
private readonly SearchView _searchView;
private IMvxAsyncCommand _command;
public SearchViewKeyPressEventsBinding(SearchView searchView) : base(searchView)
{
_searchView = searchView;
_searchView.QueryTextSubmit += _searchView_KeyPress;
}
private void _searchView_KeyPress(object sender, SearchView.QueryTextSubmitEventArgs e)
{
try
{
if (_command != null)
{
_command.ExecuteAsync();
}
}
catch (Exception ex)
{
throw ex;
}
}
public override Type TargetType
{
get { return typeof(IMvxAsyncCommand); }
}
protected override void SetValueImpl(object target, object value)
{
try
{
_command = (IMvxAsyncCommand)value;
}
catch (Exception e)
{
Log.Error("SOME BINDER FAIL\n\t" + e.Message + "\n", "SOME BINDER FAIL\n\t" + e.Message + "\n");
throw;
}
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
_searchView.QueryTextSubmit -= _searchView_KeyPress;
}
base.Dispose(isDisposing);
}
}
}
然后注册成功:
registry.RegisterFactory(new MvxCustomBindingFactory<SearchView>("OnSearchSubmit", (sv) => new SearchViewKeyPressEventsBinding(sv)))
布局中:
<SearchView
android:id="@+id/search10"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
local:MvxBind="Query SearchString; OnSearchSubmit OnSubmitPressCommand" />
并且不要忘记设置视图模型的 属性:
public IMvxAsyncCommand OnSubmitPressCommand
{
get
{
return new MvxAsyncCommand(OnSearchSubmit);
}
}
private async Task OnSearchSubmit()
{
//HideKeyboardOnSearchStart.Invoke(this, null);
await PerformBasicSearch().ConfigureAwait(false);
}