2016-05-06 21 views
1

當用戶在文本框中輸入文本時,我有一個搜索任務向便攜式類庫中的API發出請求,這可以按預期工作,但我擔心大小會影響性能。當我們有一個龐大的用戶羣,每個按鍵都向這個API發出請求時,我可以預見性能問題。Xamarin PCL - 根據用戶輸入進行API調用,如何抑制請求?

我已經限制了API調用只有在有三個以上有效字符時纔會觸發,但我想進一步抑制這一點。我可以在上面實現一個定時器,但它不像一個好的解決方案,並且不存在於PCL框架中。

是否有推薦的模式來實現這種類型的請求抑制?

private async Task GetClubs() 
    { 
     try 
     { 
      if (!string.IsNullOrWhiteSpace(ClubSearch) && ClubSearch.Replace(" ", "").Length >= 3) 
      { 
       Clubs = await dataService.GetClubs(ClubSearch); 
      } 
     } 
     catch (DataServiceException ex) 
     { 
      ... 
     } 
    } 
+0

爲什麼定時器感覺並不好? – Evk

+0

@Evk一個計時器的實現對我來說有點不好意思。這是一個有趣的話題,因爲我需要這個工作在一個不包含定時器實現的可移植類庫中。我會更新我的問題以反映這一點。 –

+0

並且Task.Delay至少可用? – Evk

回答

2

通常這是用定時器完成的。當搜索文本改變時,你開始(或重新使用)一個定時器,它將在延遲後觸發並執行搜索請求。如果在延遲期間輸入更多文本 - 定時器將被重置。示例代碼:

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

便宜/快速的方式是一個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://reactiveui.net

編號:http://docs.reactiveui.net/en/user-guide/when-any/index.html

+0

這不僅僅是每2秒執行一次服務請求嗎? – Evk

+0

@Evk是的,根據您選擇何時退出'while(true)'(即,只要SearchBar存在)每隔2秒過濾一次數據源,如果搜索文本已更改並更新Ui ... cheap /快......但我更喜歡在'ReactiveUI'中使用'命令'限制並將其綁定到我的搜索中ViewModel – SushiHangover

+0

即使沒有命令和內容,也有一種更好的方式來使用Task.Delay,而不是經常用無用的請求輪詢服務,每2秒。如果我離開午餐並離開輸入領域,該怎麼辦? – Evk