Xamarin.Android で Reactive Extensions を使う

なんか一気にハードル上がったような。。。

Reactive Extensions(Rx) については、

などを読んで頂くとして、Rx は昨年 オープンソース化され、本家を Mono for Android で使えるようにした

というプロジェクトがあります。 Mono で使えるということは Xamarin でももちろん…ということで使ってみます。

サンプルアプリケーションを作る

とりあえず Xamarin.Android で "XamarinAndroidRxSample" というプロジェクトを作りました。

RxM4A のソースを Clone する

上記のサイトからソースを取得します。以下のコマンドでもおk(要git)

$git clone https://git01.codeplex.com/rxm4a

ソリューションにプロジェクトを追加する

ソリューションツリーのソリューションのところで右クリック→追加→既存のプロジェクトを追加

"add_project"

で、先ほど取得した RxM4A のディレクトリへ移動します。

"projects"

RxMonoForAndroid の中から以下のプロジェクトを追加します。

  • System.Reactive.Interfaces
  • System.Reactive.Core
  • System.Reactive.Linq

フォルダを掘ってくと xxx.csproj ってファイルがあるので、それを選択します。 依存関係があるので、上記の順番通りやらないとなにかエラーが出ますが、最終的に3つ揃えば問題ないでしょう。

参照を追加する

XamarinAndroidRxSample から、今追加した3つのプロジェクトを参照に追加します。

ソリューションツリーの XamarinAndroidRxSample のところで右クリック→参照アセンブリの追加 から、

(画像紛失しますた)(画像紛失しますた)

ダイアログのタブで Projects を選ぶと3つ出てくるのでチェックをいれて OK してください。

Reactive Extensions を使ってみる

ボタンを押した時の処理で Rx を使ってみます。

// Main.cs
(ここまで省略)
using Android.Util;

using System.Reactive.Linq; // これ必要

namespace XamarinAndroidRxSample
{
    [Activity (Label = "XamarinAndroidRxSample", MainLauncher = true)]
    public class Activity1 : Activity
    {
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.Main);

            // Get our button from the layout resource,
            // and attach an event to it
            Button button = FindViewById<Button>(Resource.Id.myButton);

            button.Click += delegate
            {
                Observable.Range(0, 10) // 0〜9 のリスト
                .Where(n => n % 2 == 0) // 偶数だけ抽出
                .Select(n => n * 2) // 値を2倍して
                .Subscribe(n => Log.Debug("Activity1", n.ToString())); // 出力
            };
        }
    }
}

動かしてみた結果

(画像紛失しますた)

全然 Rx っぽくない(Linq だけでできる) 処理ですけど、Rx 関連クラスが使えることは確認できました。

使い倒すには、RxMonoForAndroid 配下の他のプロジェクトを参照に追加して〜となるでしょう。

アセンブリ参照はどうやるの?

ここではプロジェクト参照で行ったのですけど、各Rxプロジェクトをビルドしてできた

  • System.Reactive.Interfaces.dll
  • System.Reactive.Core.dll
  • System.Reactive.Linq.dll

をアセンブリ参照してもいいでしょ?と思ってやってみました。 それぞれの System.Reactive.Linq プロジェクトの /bin/Debug ディレクトリの中に上記ファイルができているので、てっとり早くそれを XamarinAndroidRxSample でアセンブリ参照してみました。(ほんとはちゃんと Release ビルドしてね)

そしたらアプリは動くには動いたのですが、ソリューションツリーに怪しげなエラーが↓

(画像紛失しますた)

アプリとDLLでターゲットフレームワークが違う(アプリは ICS4.0.3 でDLLは 4.0.0) だとこうなるんでしょうか? Yes、アプリ側を 4.0.0 にしてプロジェクトクリーン→Xamarin Studio を再起動したら消えました。(けどアプリの方がバージョン上位だったのに、下位互換性はどうなってるんでしょ?)

サンプルプロジェクト

これも github においておこう。RxM4A は Submodule として登録してみた。

参考