2017-05-23 2 views
2

Kurzversion: Wie implementiere ich die GetAndFetchLatest Methode wie Akavache in meinem eigenen Code (https://github.com/akavache/Akavache/blob/501b397d8c071366c3b6783aae3e98695b3d7442/src/Akavache/Portable/JsonSerializationMixin.cs#L202) - wie in ohne Akavache?Kombinieren Sie Anfragen und Ergebnisse so schnell wie möglich

Lange Version: Ich habe eine Methode, die eine Liste von T von Datenträger zurückgibt, und ich habe eine Methode, die den gleichen Typ List<T> vom HTTP-Dienst zurückgibt. Beide verpackt asynchron wie Task<List<T>>

In meiner Ansicht Modell möchte ich nur 1 Methode aufrufen, die eine Observable<List<T>> zurückgibt.

So dass ich in meinem ViewModel die .Subscribe() Methode verwenden, um die Benutzeroberfläche zu aktualisieren. Im Wesentlichen muss ich zweimal informiert werden, dass Daten verfügbar sind, und der Code im Abonnement wird auch zweimal durchgeführt.

Diese Funktion ist in Akavache in der Form der GetAndFetchLatest Methode verfügbar ... aber ich bin nicht annähernd so fließend in RX zu verstehen, wie ich dies selbst mit meinen 2 Daten Methodenaufrufen implementieren kann.

Hinweis: damit ich nicht auf beide Aufgaben warten möchte! Ich möchte beide gleichzeitig auslösen und sobald sie mit Daten zurückkommen, benachrichtigen Sie die Observable.

Irgendwelche Tipps?

Antwort

3

Bei Task<List<T>> GetFromWeb() und Task<List<T>> GetFromDisk(), die einfache Antwort ist diese:

var merged = Observable.Merge(
    GetFromWeb().ToObservable(), 
    GetFromDisk().ToObservable() 
); 

//Same thing using extension syntax 
var simply = GetFromWeb().ToObservable() 
    .Merge(GetFromDisk().ToObservable()); 

jedoch, dass nicht das unwahrscheinlich, aber möglich Szenario umgehen kann, dass GetFromWeb Oberflächen vor GetFromDisk in welchem ​​Fall ich nehme an, Sie ignorieren mögen die Ergebnisse von GetFromDisk. Zu handhaben, dass, Sie gehen Sie einige Gymnastik benötigen:

public IObservable<T> Prioritize<T>(params IObservable<T>[] orderedByDescendingPriority) 
{ 
    return orderedByDescendingPriority 
     .Select((o, i) => o.Select(item => Tuple.Create(orderedByDescendingPriority.Length - i, item))) 
     .Merge() 
     .Select(t => new Func<Tuple<int, T, bool>, Tuple<int, T, bool>>(t2 => Tuple.Create(Math.Max(t2.Item1, t.Item1), t.Item2, t.Item1 >= t2.Item1))) 
     .Scan(Tuple.Create(0, default(T), false), (t, f) => f(t)) 
     .Where(t => t.Item3) 
     .Select(t => t.Item2); 
} 

var merged = Prioritize(
    GetFromWeb().ToObservable(), 
    GetFromDisk().ToObservable() 
); 

EDIT:

Wenn Sie immer GetFromDisk wollen immer zeigen, bis vor GetFromWeb dann ist es ein einfacher Concat Betrieb. Dies funktioniert, weil .NET-Aufgaben automatisch starten, sobald Sie ihre Funktionen referenzieren:

var t1 = GetFromDisk(); 
    var t2 = GetFromWeb(); 

    var merged = Observable.Concat(
     t1.ToObservable(), 
     t2.ToObservable() 
    ); 
+0

Ooh das sieht vielversprechend aus! Lassen Sie mich das ausprobieren .... – Depechie

+0

Gibt es vielleicht eine Möglichkeit, das fromWeb-Ergebnis nicht zu priorisieren, sondern zu verzögern, nachdem das fromDisk-Ergebnis gepusht wurde? Also warte nicht mit dem Start von fromWeb, aber warte mit dem Hinzufügen der Ergebnisse zu den Observablen nachdem die von derDisk gedrängt wurden? – Depechie

+0

Also Beginne Anfragen zur gleichen Zeit, und egal wie lange 'FromDisk' dauert, wird es immer zuerst kommen, gefolgt von' FromWeb' sobald verfügbar? – Shlomo

Verwandte Themen