Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
16
Help us understand the problem. What is going on with this article?
@amay077

Xamarin に Reactive Extensions を導入する

More than 3 years have passed since last update.

昨日の ポスト を使ったのに、肝心の導入部分を説明するのを忘れていました。まあ 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 も使えてハッピーという事で、今日は以上です。

16
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
amay077
ランチの時は呼ぶといい!

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
16
Help us understand the problem. What is going on with this article?