65
Xamarin で ReactiveUI を使ってみた 2014.4.19 すまべん特別編「Xamarin 2.0であそぼう!」@関東 1

Xamarin で ReactiveUI を使ってみた

Embed Size (px)

DESCRIPTION

2014/4/19 スマートフォン勉強会(すまべん) 「Xamarin 2.0であそぼう!」@関東 の発表資料です。

Citation preview

Page 1: Xamarin で ReactiveUI を使ってみた

Xamarin で ReactiveUI を使ってみた

2014.4.19 すまべん特別編「Xamarin 2.0であそぼう!」@関東

1

Page 2: Xamarin で ReactiveUI を使ってみた

自己紹介• @amay077

• 位置情報エンジニア、モバイルアプリエンジニア、etc

• VB6→VC6→C#2.0 →Java/Obj-C→C#5.0

• Cosmoroot,Inc(Nagoya, Tokyo)

2

地図, 位置情報, オープンデータ, C#, Android, iOS,

Xamarin

“Now” Hot topics

Page 3: Xamarin で ReactiveUI を使ってみた

•        (ロジネビュラ)

• 千年先まで費用ゼロのクラウド型倉庫管理システム

•       (ジクウ)

• リアルタイム位置データ収集プラットフォーム

• Nepula(ネプラ)

• 基幹業務システム向けPaaS

おもにココ担当

クラウドサービスプロバイダ

3

Page 4: Xamarin で ReactiveUI を使ってみた

HexRinger developed atハマッカソン #2

ref http://blog.airs.co.jp/2010/12/06/hamackathon-20101204.html

4

Page 5: Xamarin で ReactiveUI を使ってみた

しゃべPOI developed forOpenStreetMappers

続きは… 位置情報系Androidアプリケーションの開発 - Togetterまとめ

5

Page 6: Xamarin で ReactiveUI を使ってみた

富士フォト with ふじのくにオープンデータMashupAward9, アーバンデータチャレンジ東京2013

ref シビックハックの広まりと地方エンジニアの躍進 ‒ MA9総括 | finder

6

Page 7: Xamarin で ReactiveUI を使ってみた

富士フォト with ふじのくにオープンデータMashupAward9, アーバンデータチャレンジ東京2013

7

iOS版は Xamarin で作りました

Page 8: Xamarin で ReactiveUI を使ってみた

おことわり• 資料内の C# コードはスペース節約のため「後ろ { カッコ」にしています

• Xamarin の勉強会なので iOS/Android 中心の話をします

• Mac が主PC なので Xamarin Studio を使っています

8

Page 9: Xamarin で ReactiveUI を使ってみた

目次

• MvvmCross ではダメ?

• Reactive Extensions について

• ReactiveUI とは

• まとめ

9

Page 10: Xamarin で ReactiveUI を使ってみた

MvvmCross

ViewModel Model

View(Droid) View(iOS)

IHogeService

HogeDroid HogeTouch

PCL

PF毎のView+DataBinding

PF固有機能(カメラ、アプリ連携、GPS…)

10

Page 11: Xamarin で ReactiveUI を使ってみた

MvvmCross• Xamarin でクロスプラットフォームアプリを開発する際の事実上標準のMVVMフレームワーク

• Android, iOS, WinStore, WP, Mac などに対応

• M-VM を PCL で共通にできる

• プラットフォーム依存機能は IoCコンテナで

11

Page 12: Xamarin で ReactiveUI を使ってみた

これで良くね?

12

Page 13: Xamarin で ReactiveUI を使ってみた

MvvmCross のデメリット• 全方位&高機能が故にFat!

• アセンブリ数:15(プラグインも入れると40over)

• チュートリアル動画が40本以上もある

• ルールたくさん(Binding、ValueConverter、Service、Plugin…)

13

Page 14: Xamarin で ReactiveUI を使ってみた

MvvmCross のデメリット• クロスプラットフォームな為、機能が最大公約数

• 前の画面からの戻り値を受け取れない(Android の onActivityResult)とか

• 各PFの最新機能に追いつけない

• iOS - Storyboard

• Android - Fragment14

Page 15: Xamarin で ReactiveUI を使ってみた

MvvmCross 以外の 選択肢

15

Page 16: Xamarin で ReactiveUI を使ってみた

QuickCross

• https://github.com/MacawNL/QuickCross

• No-Binary!

• PowerShell でコマンド叩くとコードを生成

• Mac なので試せませんでした…

16

Page 17: Xamarin で ReactiveUI を使ってみた

propertycross.com

各SDKでクロスPF開発するための指針が書いてあるみたい

圧倒的じゃないか…

17

Page 18: Xamarin で ReactiveUI を使ってみた

そして ReactiveUI

18

Page 19: Xamarin で ReactiveUI を使ってみた

…の前に !

Reactive Extensions !

について

19

Page 20: Xamarin で ReactiveUI を使ってみた

Reactive Extensionsとは

• https://rx.codeplex.com/

• 非同期処理やイベントを LINQ っぽく書いてチェインできるスゴイやつ

• TPL(async/await含む) と比べると、複数の結果を返せるのでストリーム処理に便利

20

Page 21: Xamarin で ReactiveUI を使ってみた

私とRx• Android の非同期処理でコールバック地獄

• jQuery.Deferred みたいなの欲しい

• 「.NET には Rx がある」というのを知るref:Reactive Extensionsで非同期処理を簡単に by @neueccさん「なにこれスゴイ!」

• Java には Rx ないの?

21

Page 22: Xamarin で ReactiveUI を使ってみた

Java でも Rx• reactive4java - 開発終了

• Androidアプリ開発で使ってます

• LINQ to Objects もあるよ

• RxJava

• 事実上標準の Rx for Java になる気配

• Netflix なので安心なんじゃないでしょうか22

Page 23: Xamarin で ReactiveUI を使ってみた

こうなる事は分かってた// Java - reactive4java!ObservableBuilder.range(0, 9)!.where(new Func1<Integer, Boolean>() {! @Override public Boolean invoke(Integer x) {! return x % 2 == 0;! }!}).select(new Func1<Integer, Float>() {! @Override public Float invoke(Integer x) {! return x / 2f;! }!}).register(new Observer<Float>() {! @Override public void next(Float x) { ! System.out.println(x); ! }! @Override public void finish() { }! @Override public void error(Throwable arg0) { }!});

23

// C#!Observable.Range(0, 10)!.Where(x => x % 2 == 0)!.Select(x => x / 2f)!.Subscribe(Console.WriteLine);

Page 24: Xamarin で ReactiveUI を使ってみた

で ReactiveUI とは

24

Page 25: Xamarin で ReactiveUI を使ってみた

ReactiveUI• http://www.reactiveui.net/

• Reactive Extensions を全面的に採用した MVVMフレームワーク

• WPF, WP, WinStore, iOS, Android, Mac 対応

• 元Microsoft で GitHub の中の人が作ってる

25

Page 26: Xamarin で ReactiveUI を使ってみた

MvvmCross のこれ…

ViewModel Model

View(Droid) View(iOS)

IHogeService

HogeDroid HogeTouch

PCL

26

Page 27: Xamarin で ReactiveUI を使ってみた

ReactiveUI でもできます

ViewModel Model

View(Droid) View(iOS)

IHogeService

HogeDroid HogeTouch

PCLIObservable

IObservable

IObservable

M-V-VM の「つなぎ」に Rx を使ったら…

…もっと COOL に!

27

Page 28: Xamarin で ReactiveUI を使ってみた

基本的なクラス構成

MvxViewModel : INotifyPropertyChanged

MvxActivity MvxViewController

…MvvmCross

ReactiveObject : INotifyPropertyChanged

ReactiveActivity ReactiveViewController

…ReativeUI

View ViewModel

28

Page 29: Xamarin で ReactiveUI を使ってみた

ViewModel の例public class HogeViewModel : ReactiveObject {! string _myName;! public string MyName {! get { return _myName; }! set { this.RaiseAndSetIfChanged(ref _myName, value); }! }!! public HogeViewModel() {! this.MyName = "amay077";! }!}

29

Page 30: Xamarin で ReactiveUI を使ってみた

View と Binding の例public partial class HogeViewController : ! ReactiveViewController, IViewFor<HogeViewModel> {! public override void ViewDidLoad() {! base.ViewDidLoad();!! this.OneWayBind(this.ViewModel, ! vm => vm.MyName, ! v => v.lblMyName.Text, ! x => x.ToUpper());! ! this.ViewModel = new HogeViewModel();! }!}

30

Page 31: Xamarin で ReactiveUI を使ってみた

View と Binding の例

この ViewModel の…

MyName プロパティを…

Viewのラベルに表示する…

…大文字に変換してからね

31

public partial class HogeViewController : ! ReactiveViewController, IViewFor<HogeViewModel> {! public override void ViewDidLoad() {! base.ViewDidLoad();!! this.OneWayBind(this.ViewModel, ! vm => vm.MyName, ! v => v.lblMyName.Text, ! x => x.ToUpper());! ! this.ViewModel = new HogeViewModel();! }!}

Page 32: Xamarin で ReactiveUI を使ってみた

Binding いろいろ// this = ReactiveViewController!!// 双方向 Binding!this.Bind(this.ViewModel, ! vm=> vm.MyName, v => v.EditMyText.Text);!!// コマンドに Bind!this.BindCommand(this.ViewModel, ! vm => vm.MyCommand, ! v => v.MyButton);

32

Page 33: Xamarin で ReactiveUI を使ってみた

Rx っぽい ViewModelpublic class HogeViewModel : ReactiveObject {! ObservableAsPropertyHelper<DateTime> _time;! public DateTime Time {! get { return _time.Value; }! }!! public HogeViewModel() {! _time = Observable.Interval(! TimeSpan.FromSeconds(1))! .Select(x => DateTime.Now)! .ToProperty(this, vm => vm.Time);! }!}

33

Page 34: Xamarin で ReactiveUI を使ってみた

public class HogeViewModel : ReactiveObject {! ObservableAsPropertyHelper<DateTime> _time;! public DateTime Time {! get { return _time.Value; }! }!! public HogeViewModel() {! _time = Observable.Interval(! TimeSpan.FromSeconds(1))! .Select(x => DateTime.Now)! .ToProperty(this, vm => vm.Time);! }!}

Rx っぽい ViewModel

1秒毎に…

現在時間を…

プロパティに設定する

34

Page 35: Xamarin で ReactiveUI を使ってみた

Property を IObservable へpublic class HogeViewModel : ReactiveObject {! bool _isAgreed;! public bool IsAgreed {! get { return _isAgreed; }! set { this.RaiseAndSetIfChanged(ref _isAgreed, value); }! }!! public HogeViewModel() {! IObservable<bool> agreed = ! this.ObservableForProperty(vm => vm.IsAgreed)! .Select(x => x.Value);! }!}

35

Page 36: Xamarin で ReactiveUI を使ってみた

Reactive な Commandpublic class HogeViewModel : ReactiveObject {! public bool IsAgreed { // 省略! public ICommand Register { get; private set; }!! public HogeViewModel() {! IObservable<bool> agreed = ! this.ObservableForProperty(vm => vm.IsAgreed)! .Select(x => x.Value);! var cmd = new ReactiveCommand(agreed);! cmd.Subscribe(_ => /* 実行した時の処理 */);! this.Register = cmd;! }!}

36

Page 37: Xamarin で ReactiveUI を使ってみた

View で使うpublic partial class HogeViewController : ! ReactiveViewController, IViewFor<HogeViewModel> {! public override void ViewDidLoad() {!! this.Bind(this.ViewModel, ! vm=> vm.IsAgreed, v => v.ToggleAgreed);!! this.BindCommand(this.ViewModel, ! vm=> vm.Register, v => v.RegisterButton);

37

Registerコマンドの CanExecute が true の時のみ押せる

Page 38: Xamarin で ReactiveUI を使ってみた

実行したところ

38

vm.Register.Subscribe( _=> /* 実行した時の処理 */)

Page 39: Xamarin で ReactiveUI を使ってみた

Command実行~ Property更新を 流れるように

39

Page 40: Xamarin で ReactiveUI を使ってみた

シナリオ

40

Model !

.GpsAvailable .GetLocations()

ViewModel !

.Location .StartGps()

View

bind

notify

listen

notify

Page 41: Xamarin で ReactiveUI を使ってみた

Model(適当)public class MyLocationModel {! public IObservable<bool> GpsAvailable() {! return Observable.Return(true);! }! ! public IObservable<LatLon> GetLocation() {! var r = new System.Random();! ! return Observable.Interval(TimeSpan.FromSeconds(1))! .Select(x => new LatLon(! 34d + r.NextDouble(), ! 135d + r.NextDouble()));! }!}

41

Page 42: Xamarin で ReactiveUI を使ってみた

ViewModelpublic class FourthViewModel : ReactiveObject {! MyLocationModel _model = new MyLocationModel();!! ObservableAsPropertyHelper<LatLon> _location;! public LatLon Location { get { return _location.Value; } }! ! public ICommand StartGps { get; private set; }! ! public FourthViewModel() {! var cmd = new ReactiveCommand(_model.GpsAvailable());! ! _location = cmd.SelectMany(_ => _model.GetLocation())! .ToProperty(this, vm => vm.Location);! ! this.StartGps = cmd;! }!}

42

Page 43: Xamarin で ReactiveUI を使ってみた

public class FourthViewModel : ReactiveObject {! MyLocationModel _model = new MyLocationModel();!! ObservableAsPropertyHelper<LatLon> _location;! public LatLon Location { get { return _location.Value; } }! ! public ICommand StartGps { get; private set; }! ! public FourthViewModel() {! var cmd = new ReactiveCommand(_model.GpsAvailable());! ! _location = cmd.SelectMany(_ => _model.GetLocation())! .ToProperty(this, vm => vm.Location);! ! this.StartGps = cmd;! }!}

ViewModel

43

Execute されたらモデルで測位開始、結果を逐次 Property へ

GPS が使えるなら CanExecute = true

Page 44: Xamarin で ReactiveUI を使ってみた

View は普通に Bindingpublic override void ViewDidLoad() {! base.ViewDidLoad();! ! this.OneWayBind(this.ViewModel, ! vm => vm.Location, v => v.LatLabel.Text, ! x => x.Lat.ToString("0.00"));!! this.OneWayBind(this.ViewModel, ! vm => vm.Location, v => v.LonLabel.Text, ! x => x.Lon.ToString("0.00"));! ! this.BindCommand(this.ViewModel, ! vm => vm.StartGps, v => v.StartGpsButton);! ! this.ViewModel = new FourthViewModel(); !}

44

Page 45: Xamarin で ReactiveUI を使ってみた

複合条件 (Rx を活かして)

45

Page 46: Xamarin で ReactiveUI を使ってみた

シナリオ

46

ViewModel !

.Red .Green .Blue .Color

View

bind

notifydepends

Page 47: Xamarin で ReactiveUI を使ってみた

ViewModelpublic class FifthViewModel : ReactiveObject {! float _red;! public float Red {! get { return _red; } set { this.RaiseAndSetIfChanged(ref _red, value); }! }! /* Blue, Green は省略 */!! ObservableAsPropertyHelper<Color> _color;! public Color Color { get { return _color.Value; } }!! public FifthViewModel() {! var r = this.ObservableForProperty(vm => vm.Red).Select(x => x.Value);! var g = this.ObservableForProperty(vm => vm.Green).Select(x => x.Value);! var b = this.ObservableForProperty(vm => vm.Blue).Select(x => x.Value);! ! _color = Observable.CombineLatest(r, g, b, ! (x, y, z) => new Color(x, y, z)).ToProperty(this, vm => vm.Color);! }!}

47

Page 48: Xamarin で ReactiveUI を使ってみた

public class FifthViewModel : ReactiveObject {! float _red;! public float Red {! get { return _red; } set { this.RaiseAndSetIfChanged(ref _red, value); }! }! /* Blue, Green は省略 */!! ObservableAsPropertyHelper<Color> _color;! public Color Color { get { return _color.Value; } }!! public FifthViewModel() {! var r = this.ObservableForProperty(vm => vm.Red).Select(x => x.Value);! var g = this.ObservableForProperty(vm => vm.Green).Select(x => x.Value);! var b = this.ObservableForProperty(vm => vm.Blue).Select(x => x.Value);! ! _color = Observable.CombineLatest(r, g, b, ! (x, y, z) => new Color(x, y, z)).ToProperty(this, vm => vm.Color);! }!}

ViewModel

48

3つの値が揃ったら初回設定、 以降はいずれかが変わったら設定

Page 49: Xamarin で ReactiveUI を使ってみた

View と Binding

public override void ViewDidLoad() {! this.Bind(this.ViewModel, vm => vm.Red, v => v.RedSlider.Value);! this.Bind(this.ViewModel, vm => vm.Green, v => v.GreenSlider.Value);! this.Bind(this.ViewModel, vm => vm.Blue, v => v.BlueSlider.Value);! ! this.OneWayBind(this.ViewModel, ! vm => vm.Color, ! v => v.ColorView.BackgroundColor, ! x => new UIColor(x.R, x.G, x.B, 1f));!}

49

iOSなのでUIColorに変換

Page 50: Xamarin で ReactiveUI を使ってみた

View で MultiBinding でも

public override void ViewDidLoad() {! var r = this.ObservableForProperty(v => v.ViewModel.Red)! .Select(x => x.Value);! var g = this.ObservableForProperty(v => v.ViewModel.Green)! .Select(x => x.Value);! var b = this.ObservableForProperty(v => v.ViewModel.Blue)! .Select(x => x.Value);! ! Observable.CombineLatest(r, g, b, ! (x, y, z) => new UIColor(x, y, z, 1f))! .ObserveOn(RxApp.MainThreadScheduler)! .Subscribe(x => this.ColorView.BackgroundColor = x);!}

50

UIThread で

Page 51: Xamarin で ReactiveUI を使ってみた

ところで 今まで紹介したこれ

51

Page 52: Xamarin で ReactiveUI を使ってみた

ReactiveProperty の方が イケてますよね

52

http://reactiveproperty.codeplex.com/

Page 53: Xamarin で ReactiveUI を使ってみた

スッキリ!public class FifthViewModel {! public ReactiveProperty<float> Red { get; private set; }! public ReactiveProperty<float> Green { get; private set; }! public ReactiveProperty<float> Blue { get; private set; }!! public ReactiveProperty<Color> Color { get; private set; }!! public FifthViewModel() {! ! this.Color = Observable.CombineLatest(Red, Green, Blue, ! (x, y, z) => new Color(x, y, z)).ToReactiveProperty();!! }!}

53

Page 54: Xamarin で ReactiveUI を使ってみた

ReactiveUI で画面遷移• MvvmCross では

• ShowViewModel<NextViewModel>()

• ReactiveUI だと

• Router.NavigateCommandFor<NextViewModel>() - 参照

• が、iOS/Android では未対応のようで…54

Page 55: Xamarin で ReactiveUI を使ってみた

画面遷移• 画面遷移はプラットフォーム毎に仕組みが違って、しかも進化が早い

• MvvmCross も、iOS の Storyboard に対応し切れていない

• 割りきって View に画面遷移コードを書くか、Resolver(後述)を使って自作する

55

Page 56: Xamarin で ReactiveUI を使ってみた

IoC というか DI というか• MvvmCross では

• Service を使う by @iseebiさん

• ルールに従えば Resolver を意識することない

• ReactiveUI では

• RxApp.MutableResolver を使う

• 全てコードを書く必要あり56

Page 57: Xamarin で ReactiveUI を使ってみた

Resolver の仕組み

r = RxUI.Resolver

HogeDroid (Android)

HogeTouch (iOS)

Model

IHogeService

r.Register(()=>new HogeDroid(), typeOf(IHogeService))

var svc = r.GetService<IHogeService>()

…PCL57

Page 58: Xamarin で ReactiveUI を使ってみた

public partial class AppDelegate : UIApplicationDelegate {! public override bool FinishedLaunching(! UIApplication app, NSDictionary options) {!! var r = RxApp.MutableResolver;! ! r.Register(! () => new HogeTouch(), ! typeof(IHogeService));!または! r.RegisterLazySingleton(! () => new HogeTouch(), ! typeof(IHogeService));

Resolver へ登録

58

都度インスタンスを生成

初回1回だけ、あと使い回し

Page 59: Xamarin で ReactiveUI を使ってみた

Resolver を使って インスタンス化

// Model(PCL) にて!!IHogeService svc = ! RxApp.MutableResolver.GetService<IHogeService>();!!svc.SomeMethod(); // 実体は Resolver に登録したクラス

59

Page 60: Xamarin で ReactiveUI を使ってみた

まとめ

60

Page 61: Xamarin で ReactiveUI を使ってみた

ReactiveUI のメリット

• Rx で、(主に)ViewModel のコードを削減

• IoCコンテナ(Resolver)でPF固有機能を解決

• iOS/Android/WPF などの DataBinding が用意されている

61

Page 62: Xamarin で ReactiveUI を使ってみた

参考リンク• neue cc http://neue.cc/

• かずきのBlog@hatenahttp://okazuki.hatenablog.com/

• Rx入門 | xin9le.net http://xin9le.net/rx-intro

• GitHub's Xamarin starter apps http://log.paulbetts.org/open-source-githubs-xamarin-starter-apps/

62

Page 63: Xamarin で ReactiveUI を使ってみた

ありがとうございました

63

Page 64: Xamarin で ReactiveUI を使ってみた

おまけ• Rx も PCL 化されましたが、

• Android用、iOS用のSystem.Reactive.PlatformServices.dll は、どこに?あるいはどうやってビルドしたらよいでしょう?

• あと PlatformServices.dll はiOS の AOT で問題なく使えるのでしょうか?

• ref:https://twitter.com/atsushieno/status/457399573363712000

64

Page 65: Xamarin で ReactiveUI を使ってみた

おまけ

• PCL の Profile に Silverlight を含めると IObservable が無くなってしまうので実質SLは(ry

• Profile78 This is Xamarin's current preferred profile.とのこと。

65