0

Im Разработка приложения Xamarin.Ios little dictionary, он отправляет запрос GET на сервер и возвращает значение по ключу (слово), ввод текста на SearchBar, и я наблюдаю на его событии TextChanged, хорошо, что мне удалось отправить запрос наблюдаемыми, но я хочу показать LoadView, если Request занимает более 1 или 2 секунды ... Я попробовал Buffer(), но он сделал не работает, так вот код спасибо!Rx Показать Загрузка (индикатор выполнения или что-то в этом роде) Если веб-запрос занимает слишком много времени

var dataStream = Observable.FromEventPattern<UISearchBarTextChangedEventArgs>(ev => searchBar.TextChanged += ev, 
         ev => searchBar.TextChanged -= ev) 
    .Select(o => o.EventArgs.SearchText) 
    .DistinctUntilChanged() 
    .Throttle(TimeSpan.FromMilliseconds(300)) 
    .ObserveOn(SynchronizationContext.Current) 
    .Select(t => 
    { 
     #if DEBUG 
      Console.WriteLine(t); 
     #endif 
     var instance = TranslateWebClient.Instance;//this is WebClient From where Get Request is made 
     var data = instance.GetWordAsync(t); 
     return data.ToObservable().ObserveOn(SynchronizationContext.Current); 
    }) 
.Switch(); 

dataStream.Subscribe(o => 
{ 
    if (o == null || o.Count() == 0) 
    { 
     wordsTableView.DataSource = null; 
     wordsTableView.ReloadData(); 
     return; 
    } 
    _words = o; 
    initDataToUI(); 
}, ex => 
{ 
    if (ex is WebClient.NoInternetException) 
    { 
     //handle exception 
    } 
}); 
+0

либо используют асинхронные версии вызовов, либо завершают их в «ждут Task.Run» –

ответ

3

Поэтому я думаю, что что-то подобное будет работать. Добавьте это перечисление, или использовать что-то подобное, если имеется:

enum LoadState 
{ 
    InitialState, 
    RequestSent, 
    ResponseLate, 
    ResponseReceived 
} 

... затем измените dataStream заявление на следующее:

var requestStream = Observable.FromEventPattern<UISearchBarTextChangedEventArgs>(ev => searchBar.TextChanged += ev, 
         ev => searchBar.TextChanged -= ev) 
    .Select(o => o.EventArgs.SearchText) 
    .DistinctUntilChanged() 
    .Throttle(TimeSpan.FromMilliseconds(300)) 
    .ObserveOn(SynchronizationContext.Current) 
    .Select(t => 
    { 
#if DEBUG 
     Console.WriteLine(t); 
#endif 
    var instance = TranslateWebClient.Instance;//this is WebClient From where Get Request is made 
    var data = instance.GetWordAsync(t); 
     return data.ToObservable().ObserveOn(SynchronizationContext.Current); 
    }) 
    .Publish() 
    .RefCount(); 

requestStream 
    .SelectMany(o => Observable.Merge(
     Observable.Return(LoadState.RequestSent), 
     Observable.Timer(TimeSpan.FromSeconds(1)).Select(_ => LoadState.ResponseLate), 
     o.Select(_ => LoadState.ResponseReceived)) 
    ) 
    .Scan(LoadState.InitialState, 
     (previousState, newState) => previousState == LoadState.ResponseReceived && newState == LoadState.ResponseLate 
      ? LoadState.ResponseReceived 
      : newState 
    ) 
    .Subscribe(state => 
    { 
     if(state == LoadState.ResponseLate) 
      ; //enable loading UI 
     else 
      ; //disable loading UI 
    }); 

var dataStream = requestStream.Switch(); 

Объяснение: requestStream излучает наблюдаемым, представляющий веб-каждый запрос. Новая подписка, на мой взгляд, соответствует бизнес-правилам, которые вы имеете в виду: отображение ожидающего пользовательского интерфейса, когда задержка достигнет 1 секунды или более, а затем отмените ожидающий пользовательский интерфейс, если они сделают новый запрос или ответ будет получен.

+1

Nice. Я писал очень похожее решение, но боролся с обработкой состояния с помощью 'Scan' – supertopi

+1

вам нужно добавить ObserveOn после сканирования, спасибо большое! Это сэкономит мой день :) – Lekve

Смежные вопросы