1

次のように定義された、Reactive Extensions を使用した 3 つのサービス メソッドのセットを使用する Windows Phone 7 アプリケーションがあります。

public static class ServiceClient
{
    public static IObservable<string> LookupImage(byte[] image) {...}

    public static IObservable<XDocument> GetDefinition(string id) {...}

    public static IObservable<Dictionary<string, byte[]>> GetFiles(string id, string[] fileNames) {...}                
}

返される値が空でなくなるまで、WP7 アプリケーションLookupImageが上記のクライアントを (毎回異なるbyte[] imageデータ セットで)呼び出し続ける必要があります。IObservable<string>文字列を取得したら、メソッドとメソッドを (この順序で)Observable呼び出す必要があります。GetDefinitionGetFiles

への呼び出しはLookupImage、タイマーによって制御されるのではなく、サービス応答が返されるたびに発生する必要があります。これは、ネットワーク接続速度によって異なるため、可能な限り多くの呼び出しを送信できる必要があるためです。

上記の解決策となる可能性のあるものへのポインタをいただければ幸いです。手始めに、私は次のものを持っています

private void RunLookupAndRenderLogic()
{   
   byte[] imageBytes = GetImageBytes();

   // There are some cases where the image was not 'interesting' enough in which case GetImageBytes() returns null
   if (pictureBytes != null)
   {
      // Where we have image data, send this to LookupImage service method
      var markerLookup = ServiceClient.LookupImage(imageBytes);

      markerLookup.Subscribe(id =>      
        {
                       // If the id is empty, we need to call this again.
                       if (String.IsNullOrEmpty(id))
                       {
                            ???
                       }

                       // If we have an id, call GetDefinition and GetFiles methods of the service. No further calls to LookupImage should take place.
                       RenderLogic(id);   
     });
  }
  else
   // If no interesting image was returned, try again
   RunRecognitionAndRenderLogic();
}
4

1 に答える 1

1

間違っていたら申し訳ありませんが、私の理解が正しければ、値が返されるまで、まったく同じ引数で LookupImage の呼び出しを再試行してください。

これを解決する簡単な方法は、repeat を呼び出してから take(1) を呼び出すことです。

ServiceClient.LookupImage(imageBytes)
    .Repeat()
    .Take(1)
    .Subscribe(id =>  ....);

ただし、Rx はデフォルトでシングル スレッドであるため、このコンテキストでは破棄呼び出しを挿入できるポイントはありません (Take(1)-->OnComplete()--> サブスクリプションの自動破棄から暗黙的に)。

CurrentThread スケジューラを使用して、後続の再サブスクリプションの間に息抜きのスペースを提供することで、これを回避できます。

Observable.Defer(()=>
    ServiceClient.LookupImage(imageBytes)
                 .ObserveOn(Scheduler.CurrentThread)
    )
    .Repeat()
    .Take(1)
    .Subscribe(id =>  ....);

Rx をある程度理解し、創造性を働かせれば、これを実現する方法は他にもあります。(ほとんどの場合、スケジューラを想像します)

インスピレーションを得るには、 Scheduling and Threading の章を参照してください。再帰と、実際にやろうとしている独自のイテレータの構築について説明します。

完全なコード サンプル:

private void RunLookupAndRenderLogic()
{   
    byte[] imageBytes = GetImageBytes();

    // There are some cases where the image was not 'interesting' enough in which case GetImageBytes() returns null
    if (pictureBytes != null)
    {
        // Where we have image data, send this to LookupImage service method
        var subscription = Observable
        .Defer(()=>
            ServiceClient.LookupImage(imageBytes)
                     .ObserveOn(Scheduler.CurrentThread)
        )
        .Where(id=>!String.IsNullOrEmpty(id))
        .Repeat()
        .Take(1)
        .Subscribe(id =>      
        {
           // If we have an id, call GetDefinition and GetFiles methods of the service. No further calls to LookupImage should take place.
           RenderLogic(id);   
        });

        //TODO: You dont offer any way to cancel this (dispose of the suscription). 
        //This means you could loop forever :-(
    }
    else
    {
        // If no interesting image was returned, try again
        RunRecognitionAndRenderLogic();
    }
}

(開示: 私は IntroToRx.com の作成者です)

于 2012-11-02T15:31:03.730 に答える