Xamarin PCL - 根据用户输入进行 API 调用,如何抑制请求?
Xamarin PCL - Making API calls based on user entry, how to dampen requests?
我有一个搜索任务,在便携式 class 库中向 API 发出请求,当用户在文本框中输入文本时,这按预期工作,但我有一个问题规模上的过度表现。当我们有一个庞大的用户群时,在每次按键时都向这个 API 发出请求,我可以预见到性能问题。
我已将 API 调用限制为仅在超过三个有效字符时触发,但我想进一步抑制这种情况。我可以在此基础上实现一个计时器,但感觉它不是一个好的解决方案,并且不存在于 PCL 框架中。
是否有推荐的模式来实现此类请求抑制?
private async Task GetClubs()
{
try
{
if (!string.IsNullOrWhiteSpace(ClubSearch) && ClubSearch.Replace(" ", "").Length >= 3)
{
Clubs = await dataService.GetClubs(ClubSearch);
}
}
catch (DataServiceException ex)
{
...
}
}
通常这是用定时器来完成的。当搜索文本更改时,您启动(或重复使用)一个计时器,该计时器将在延迟后触发并执行搜索请求。如果在该延迟期间键入了更多文本 - 计时器将重置。示例代码:
public class MyClass {
private readonly Timer _timer;
const int ThrottlePeriod = 500; // ms
public MyClass() {
_timer = new System.Threading.Timer(_ => {
ExecuteRequest();
}, null, Timeout.Infinite, Timeout.Infinite);
}
private string _searchTerm;
public string SearchTerm
{
get { return _searchTerm; }
set
{
_searchTerm = value;
ResetTimer();
}
}
private void ResetTimer() {
_timer.Change(ThrottlePeriod, Timeout.Infinite);
}
private void ExecuteRequest() {
Console.WriteLine(SearchTerm);
}
}
如果定时器不可用,你可以用Task.Delay做同样的事情:
public class MyClass
{
const int ThrottlePeriod = 500; // ms
private string _searchTerm;
public string SearchTerm
{
get { return _searchTerm; }
set
{
_searchTerm = value;
SearchWithDelay();
}
}
private async void SearchWithDelay() {
var before = this.SearchTerm;
await Task.Delay(ThrottlePeriod);
if (before == this.SearchTerm) {
// did not change while we were waiting
ExecuteRequest();
}
}
private void ExecuteRequest()
{
Console.WriteLine(SearchTerm);
}
}
Cheap/Fast 实现方法是 Task.Delay
:
var mySearchThread = new Thread (new ThreadStart (async delegate {
while (true) {
if (!String.IsNullOrWhiteSpace(seachText) {
YourSearchMethod(seachText)
};
InvokeOnMainThread ( () => {
// Refresh your datasource on the UIthread
});
await Task.Delay (2000);
}
})).Start ();
基于 PCL 的解决方案(以及使用 出色框架 的惊人干净方式)是使用 ReactiveUI
节流 (Throttle
),那么你可以做这样的壮举:
// Throttle searching to every 2 seconds
this.WhenAnyValue(x => x.SearchText)
.Where(x => !String.IsNullOrWhiteSpace(x))
.Throttle(TimeSpan.FromSeconds(2))
.InvokeCommand(SearchCommand)
参考:http://docs.reactiveui.net/en/user-guide/when-any/index.html
我有一个搜索任务,在便携式 class 库中向 API 发出请求,当用户在文本框中输入文本时,这按预期工作,但我有一个问题规模上的过度表现。当我们有一个庞大的用户群时,在每次按键时都向这个 API 发出请求,我可以预见到性能问题。
我已将 API 调用限制为仅在超过三个有效字符时触发,但我想进一步抑制这种情况。我可以在此基础上实现一个计时器,但感觉它不是一个好的解决方案,并且不存在于 PCL 框架中。
是否有推荐的模式来实现此类请求抑制?
private async Task GetClubs()
{
try
{
if (!string.IsNullOrWhiteSpace(ClubSearch) && ClubSearch.Replace(" ", "").Length >= 3)
{
Clubs = await dataService.GetClubs(ClubSearch);
}
}
catch (DataServiceException ex)
{
...
}
}
通常这是用定时器来完成的。当搜索文本更改时,您启动(或重复使用)一个计时器,该计时器将在延迟后触发并执行搜索请求。如果在该延迟期间键入了更多文本 - 计时器将重置。示例代码:
public class MyClass {
private readonly Timer _timer;
const int ThrottlePeriod = 500; // ms
public MyClass() {
_timer = new System.Threading.Timer(_ => {
ExecuteRequest();
}, null, Timeout.Infinite, Timeout.Infinite);
}
private string _searchTerm;
public string SearchTerm
{
get { return _searchTerm; }
set
{
_searchTerm = value;
ResetTimer();
}
}
private void ResetTimer() {
_timer.Change(ThrottlePeriod, Timeout.Infinite);
}
private void ExecuteRequest() {
Console.WriteLine(SearchTerm);
}
}
如果定时器不可用,你可以用Task.Delay做同样的事情:
public class MyClass
{
const int ThrottlePeriod = 500; // ms
private string _searchTerm;
public string SearchTerm
{
get { return _searchTerm; }
set
{
_searchTerm = value;
SearchWithDelay();
}
}
private async void SearchWithDelay() {
var before = this.SearchTerm;
await Task.Delay(ThrottlePeriod);
if (before == this.SearchTerm) {
// did not change while we were waiting
ExecuteRequest();
}
}
private void ExecuteRequest()
{
Console.WriteLine(SearchTerm);
}
}
Cheap/Fast 实现方法是 Task.Delay
:
var mySearchThread = new Thread (new ThreadStart (async delegate {
while (true) {
if (!String.IsNullOrWhiteSpace(seachText) {
YourSearchMethod(seachText)
};
InvokeOnMainThread ( () => {
// Refresh your datasource on the UIthread
});
await Task.Delay (2000);
}
})).Start ();
基于 PCL 的解决方案(以及使用 出色框架 的惊人干净方式)是使用 ReactiveUI
节流 (Throttle
),那么你可以做这样的壮举:
// Throttle searching to every 2 seconds
this.WhenAnyValue(x => x.SearchText)
.Where(x => !String.IsNullOrWhiteSpace(x))
.Throttle(TimeSpan.FromSeconds(2))
.InvokeCommand(SearchCommand)
参考:http://docs.reactiveui.net/en/user-guide/when-any/index.html