13
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

XamarinAdvent Calendar 2013

Day 12

Xamarin に Reactive Extensions を導入する

Last updated at Posted at 2013-12-11

昨日の ポスト を使ったのに、肝心の導入部分を説明するのを忘れていました。まあ Components から追加するだけなのですが。他のアドベントカレンダーとの掛け持ちで疲れたので、今日は軽く書いて済ませます。

Reactive Extensions を導入する

Components で右クリック → Get more components → Reactive とかで検索 → 見つけたら Add to App で OK です。あ、この手順は .iOS でも .Android でも同じです。

使ってみましょうか

イベントを Stream に変換する例を示してお茶を濁します。

まずこんな感じのどうでもいい画面を用意しまして、

UIButton.TouchUpInsideIObservable に変換する拡張メソッドを用意します。

UIButtonExtensions.cs
public static class UIButtonExtensions
{
    public static IObservable<string> ClickAsObservable(this UIButton button)
    {
        return Observable.FromEventPattern(
            h => button.TouchUpInside+=h, 
            h => button.TouchUpInside-=h)
        .Select(e => ((UIButton)e.Sender).TitleLabel.Text);
    }
}

2014.5.14 追記

Observable.FromEventPattern<EventArgs>(button, "TouchUpInside") このメソッドは、iOS の実機で動作しません。詳しくは、Xamarin.iOS で FromEventPattern を使うときの注意点 で書きましたが、実機では AOT のためリフレクションが使えないからです。
代わりに、 += と -= の delegate を引数に取るオーバーロードを使います。

追記ここまで

で、こんなコードを書きます。

MainViewController_amb.cs
public override void ViewDidLoad()
{
    base.ViewDidLoad();

    Button1.ClickAsObservable()
        .Publish(_ => 
            Button2.ClickAsObservable()
            .Amb(
                Button3.ClickAsObservable()))
        .Subscribe(btnName => InvokeOnMainThread(() => 
            Label1.Text = btnName + " Clicked"));
}

Observable.Amb (先にきた値を流す)

Button1 を押すと処理の開始です。
Publish で分配して Amb は Button2 のクリックと Button3 のクリックで先に行われた方を Label1 に表示します。

Observable.Zip (どちらの値も待つ)

Amb を Zip に変えてみます。

MainViewController_zip.cs
    Button1.ClickAsObservable()
        .Publish(_ => 
            Button2.ClickAsObservable()
            .Zip(
                Button3.ClickAsObservable(), (l,r) => new {l, r}))
        .Subscribe(p => InvokeOnMainThread(() => 
            Label1.Text = p.l + " and " + p.r + "Clicked"));

Zip は2つのシーケンスの結果を待ってから後続へ流します。
なので、Button2 と Button3 の両方が押されると、Label1 に表示されます。

どちらもフツーに書くとフラグ変数なんか使って実現すると思うんですけど、Rx を使うと読みやすいコードになると思います。

あと、私は Android-Java の開発では reactive4Java を使ってるんですが、あれには Observable.FromEventPattern が無い(Java のイベントの Listener はイベントのマルチキャストに対応してないから仕方ない)ので、Xamarin にすることで「完全な」Rx を使うことができて、こりゃ勉強のしがいがあるなあと思ったのでした。

何の記事でしたっけ?という感じですけど Xamarin なら Linq も Rx も使えてハッピーという事で、今日は以上です。

13
16
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?