Xamarin で ReactiveUI を使ってみた

  • 970 views
Uploaded on

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

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

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
970
On Slideshare
0
From Embeds
0
Number of Embeds
4

Actions

Shares
Downloads
5
Comments
0
Likes
9

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Xamarin で ReactiveUI を使ってみた 2014.4.19 すまべん特別編「Xamarin 2.0であそぼう!」@関東 1
  • 2. 自己紹介 • @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
  • 3. •        (ロジネビュラ) • 千年先まで費用ゼロのクラウド型倉庫管理システム •       (ジクウ) • リアルタイム位置データ収集プラットフォーム • Nepula(ネプラ) • 基幹業務システム向けPaaS おもにココ担当 クラウドサービスプロバイダ 3
  • 4. HexRinger developed at ハマッカソン #2 ref http://blog.airs.co.jp/2010/12/06/hamackathon-20101204.html 4
  • 5. しゃべPOI developed for OpenStreetMappers 続きは… 位置情報系Androidアプリケーションの開発 - Togetterまとめ 5
  • 6. 富士フォト with ふじのくにオープンデータ MashupAward9, アーバンデータチャレンジ東京2013 ref シビックハックの広まりと地方エンジニアの躍進 ‒ MA9総括 ¦ finder 6
  • 7. 富士フォト with ふじのくにオープンデータ MashupAward9, アーバンデータチャレンジ東京2013 7 iOS版は Xamarin で 作りました
  • 8. おことわり • 資料内の C# コードはスペース節約のため「後 ろ { カッコ」にしています • Xamarin の勉強会なので iOS/Android 中心の 話をします • Mac が主PC なので Xamarin Studio を使って います 8
  • 9. 目次 • MvvmCross ではダメ? • Reactive Extensions について • ReactiveUI とは • まとめ 9
  • 10. MvvmCross ViewModel Model View(Droid) View(iOS) IHogeService HogeDroid HogeTouch PCL PF毎のView+DataBinding PF固有機能(カメラ、アプリ連 携、GPS…) 10
  • 11. MvvmCross • Xamarin でクロスプラットフォームアプリを開 発する際の事実上標準のMVVMフレームワーク • Android, iOS, WinStore, WP, Mac などに対応 • M-VM を PCL で共通にできる • プラットフォーム依存機能は IoCコンテナで 11
  • 12. これで良くね? 12
  • 13. MvvmCross のデメリット • 全方位&高機能が故にFat! • アセンブリ数:15(プラグインも入れると 40over) • チュートリアル動画が40本以上もある • ルールたくさん(Binding、ValueConverter、 Service、Plugin…) 13
  • 14. MvvmCross のデメリット • クロスプラットフォームな為、機能が最大公約数 • 前の画面からの戻り値を受け取れない(Android の onActivityResult)とか • 各PFの最新機能に追いつけない • iOS - Storyboard • Android - Fragment 14
  • 15. MvvmCross 以外の 選択肢 15
  • 16. QuickCross • https://github.com/MacawNL/QuickCross • No-Binary! • PowerShell でコマンド叩くとコードを生成 • Mac なので試せませんでした… 16
  • 17. propertycross.com 各SDKでクロスPF開発するための指針が書いてあるみたい 圧倒的じゃないか… 17
  • 18. そして ReactiveUI 18
  • 19. …の前に ! Reactive Extensions ! について 19
  • 20. Reactive Extensionsとは • https://rx.codeplex.com/ • 非同期処理やイベントを LINQ っぽく書いてチェ インできるスゴイやつ • TPL(async/await含む) と比べると、複数の結果 を返せるのでストリーム処理に便利 20
  • 21. 私とRx • Android の非同期処理でコールバック地獄 • jQuery.Deferred みたいなの欲しい • 「.NET には Rx がある」というのを知る
 ref:Reactive Extensionsで非同期処理を簡単に by @neueccさん
 「なにこれスゴイ!」 • Java には Rx ないの? 21
  • 22. Java でも Rx • reactive4java - 開発終了 • Androidアプリ開発で使ってます • LINQ to Objects もあるよ • RxJava • 事実上標準の Rx for Java になる気配 • Netflix なので安心なんじゃないでしょうか 22
  • 23. こうなる事は分かってた // 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);
  • 24. で ReactiveUI とは 24
  • 25. ReactiveUI • http://www.reactiveui.net/ • Reactive Extensions を全面的に採用した MVVMフレームワーク • WPF, WP, WinStore, iOS, Android, Mac 対応 • 元Microsoft で GitHub の中の人が作ってる 25
  • 26. MvvmCross のこれ… ViewModel Model View(Droid) View(iOS) IHogeService HogeDroid HogeTouch PCL 26
  • 27. ReactiveUI でもできます ViewModel Model View(Droid) View(iOS) IHogeService HogeDroid HogeTouch PCL IObservable IObservable IObservable M-V-VM の「つなぎ」に Rx を使ったら… …もっと COOL に! 27
  • 28. 基本的なクラス構成 MvxViewModel : INotifyPropertyChanged MvxActivity MvxViewController … MvvmCross ReactiveObject : INotifyPropertyChanged ReactiveActivity ReactiveViewController … ReativeUI View ViewModel 28
  • 29. 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
  • 30. 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
  • 31. 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();! }! }
  • 32. 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
  • 33. Rx っぽい ViewModel 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);! }! } 33
  • 34. 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
  • 35. 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
  • 36. Reactive な Command public 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
  • 37. 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 の時のみ押せる
  • 38. 実行したところ 38 vm.Register.Subscribe( _=> /* 実行した時の処理 */)
  • 39. Command実行∼ Property更新を 流れるように 39
  • 40. シナリオ 40 Model ! .GpsAvailable .GetLocations() ViewModel ! .Location .StartGps() View bind notify listen notify
  • 41. 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
  • 42. ViewModel 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;! }! } 42
  • 43. 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
  • 44. View は普通に Binding public 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
  • 45. 複合条件 (Rx を活かして) 45
  • 46. シナリオ 46 ViewModel ! .Red .Green .Blue .Color View bind notify depends
  • 47. ViewModel 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);! }! } 47
  • 48. 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つの値が ったら初回設定、 以降はいずれかが変わったら設定
  • 49. 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に変換
  • 50. 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 で
  • 51. ところで 今まで紹介したこれ 51
  • 52. ReactiveProperty の方が イケてますよね 52 http://reactiveproperty.codeplex.com/
  • 53. スッキリ! 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
  • 54. ReactiveUI で画面遷移 • MvvmCross では • ShowViewModel<NextViewModel>() • ReactiveUI だと • Router.NavigateCommandFor<NextViewMo del>() - 参照 • が、iOS/Android では未対応のようで… 54
  • 55. 画面遷移 • 画面遷移はプラットフォーム毎に仕組みが違って、 しかも進化が早い • MvvmCross も、iOS の Storyboard に対応し 切れていない • 割りきって View に画面遷移コードを書くか、
 Resolver(後述)を使って自作する 55
  • 56. IoC というか DI というか • MvvmCross では • Service を使う by @iseebiさん • ルールに従えば Resolver を意識することない • ReactiveUI では • RxApp.MutableResolver を使う • 全てコードを書く必要あり 56
  • 57. Resolver の仕組み r = RxUI.Resolver HogeDroid (Android) HogeTouch (iOS) Model IHogeService r.Register(()=>new HogeDroid(), typeOf(IHogeService)) var svc = r.GetService<IHogeService>() …PCL 57
  • 58. 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回だけ、あと使い回し
  • 59. Resolver を使って インスタンス化 // Model(PCL) にて! ! IHogeService svc = ! RxApp.MutableResolver.GetService<IHogeService>();! ! svc.SomeMethod(); // 実体は Resolver に登録したクラス 59
  • 60. まとめ 60
  • 61. ReactiveUI のメリット • Rx で、(主に)ViewModel のコードを削減 • IoCコンテナ(Resolver)でPF固有機能を解決 • iOS/Android/WPF などの DataBinding が用意 されている 61
  • 62. 参考リンク • neue cc 
 http://neue.cc/ • かずきのBlog@hatena
 http://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
  • 63. ありがとうございました 63
  • 64. おまけ • Rx も PCL 化されましたが、 • Android用、iOS用のSystem.Reactive.PlatformServices.dll
 は、どこに?
 あるいはどうやってビルドしたらよいでしょう? • あと PlatformServices.dll は
 iOS の AOT で問題なく使えるのでしょうか? • ref:https://twitter.com/atsushieno/status/ 457399573363712000 64
  • 65. おまけ • PCL の Profile に Silverlight を含めると IObservable が無くなってしまうので実質SLは (ry • Profile78 
 This is Xamarin's current preferred profile.
 とのこと。 65