UniRxを使ってみる
ここではUniRxの基本的なオペレータとそのサンプルコードを見ていきたいと思います。
概念を理解するのも大切ですが実際に使って動かしてみるのも理解への近道です。
全体のコードは以下のリポジトリにありますので、別記事の UnityでLINQを使って楽をする も合わせてご覧ください。
また、本記事は全体的に以下のサイトの記事(RxJava)を参考にさせて頂きました。
What's UniRx?
http://slides.com/robwormald/everything-is-a-stream#/
特徴
- ReactiveXのUnity版
- マーブルダイアグラム
- Observable / Subscribe の世界
- 豊富なオペレータ
- 非同期並列処理
- Asset StoreからUniRxをImportして
using UniRx
で使えるようになるよ
Timer
指定時間後に処理を行います。
using UniRx; using System; Debug.Log("Timer START"); Observable.Timer(TimeSpan.FromSeconds(3)) .Subscribe(_ => Debug.Log("OK")); // 3秒後に"OK"
Interval
指定時間間隔で繰り返します。
using UniRx; using System; Observable .Interval(TimeSpan.FromSeconds(1)) .Subscribe(x => Debug.Log(x)); // 0, 1, 2, 3, 4, 5......
Where
条件式がTrueとなるものを流します。
using UniRx; var list = new List<int> { 1, 2, 3, 4, 5 }; list.ToObservable() .Where(x => x > 2) .Subscribe(x => Debug.Log(x)); // 3, 4, 5
Distinct
重複を削除します。
using UniRx; var list = new List<int> { 1, 2, 3, 3, 4, 5, 5 }; list.ToObservable() .Distinct() .Subscribe(x => Debug.Log(x)); // 1, 2, 3, 4, 5
Take
指定回数だけ流します。
using UniRx; var list = new List<int> { 1, 2, 3, 4, 5 }; list.ToObservable() .Take(3) .Subscribe(x => Debug.Log(x)); // 1, 2, 3
Skip
指定回数だけスキップします。
using UniRx; var list = new List<int> { 1, 2, 3, 4, 5 }; list.ToObservable() .Skip(3) .Subscribe(x => Debug.Log(x)); // 4, 5
Scan
畳み込みを行います。
using UniRx; var list = new List<int> { 1, 2, 3, 4, 5 }; list.ToObservable() .Scan((a, b) => a + b) .Subscribe(x => Debug.Log(x)); // 1, 3, 6, 10, 15
Range
範囲を指定して流します。
using UniRx; Observable .Range(1, 5) .Subscribe(x => Debug.Log(x)); // 1, 2, 3, 4, 5
Create
Observableを作成します。
using UniRx; var observable = Observable.Create<int>(observer => { observer.OnNext(1); observer.OnNext(2); observer.OnNext(3); observer.OnNext(4); observer.OnNext(5); observer.OnCompleted(); return Disposable.Empty; }); observable.Subscribe(x => Debug.Log(x)); // 1, 2, 3, 4, 5
ボタンクリックイベント
OnClickイベントをObservable化します。
using UniRx; using UnityEngine.UI; [SerializeField] Button button = default; button .OnClickAsObservable() .Subscribe(_ => Debug.Log("on click"));
SubscribeOn
Observerを処理するスレッドを指定します。
using UniRx; using System.Threading; Debug.Log("START"); var observable = Observable.Create<int>(observer => { Thread.Sleep(3000); observer.OnNext(1); observer.OnCompleted(); return Disposable.Empty; }).SubscribeOn(Scheduler.ThreadPool); observable.Subscribe(x => Debug.Log(x)); Debug.Log("END"); // START // END // 1 (3秒後)
Merge
Observableを合成します。順不同
using UniRx; using System.Threading; var list1 = Observable.Create<string>(observer => { Thread.Sleep(1); observer.OnNext("A1"); Thread.Sleep(8); observer.OnNext("A2"); Thread.Sleep(2); observer.OnNext("A3"); observer.OnCompleted(); return Disposable.Empty; }).SubscribeOn(Scheduler.ThreadPool); var list2 = Observable.Create<string>(observer => { Thread.Sleep(3); observer.OnNext("B1"); Thread.Sleep(1); observer.OnNext("B2"); Thread.Sleep(12); observer.OnNext("B3"); observer.OnCompleted(); return Disposable.Empty; }).SubscribeOn(Scheduler.ThreadPool); Observable .Merge(list1, list2) .Subscribe(x => Debug.Log(x)); // A1, B1, B2, A2, A3, B3
Concat
Observableを合成します。流れる順序は引数受け取り順です。
using UniRx; using System.Threading; var list1 = Observable.Create<string>(observer => { Thread.Sleep(1); observer.OnNext("A1"); Thread.Sleep(8); observer.OnNext("A2"); Thread.Sleep(2); observer.OnNext("A3"); observer.OnCompleted(); return Disposable.Empty; }).SubscribeOn(Scheduler.ThreadPool); var list2 = Observable.Create<string>(observer => { Thread.Sleep(3); observer.OnNext("B1"); Thread.Sleep(1); observer.OnNext("B2"); Thread.Sleep(12); observer.OnNext("B3"); observer.OnCompleted(); return Disposable.Empty; }).SubscribeOn(Scheduler.ThreadPool); Observable .Concat(list1, list2) .Subscribe(x => Debug.Log(x)); // A1, A2, A3, B1, B2, B3
Zip
MergeやConcatとの違いは異なる型のObservableを扱えます。
using UniRx; var list1 = new List<string> { "A", "B", "C", "D", "E" }.ToObservable(); var list2 = new List<int> { 1, 2, 3, 4, 5 }.ToObservable(); Observable .Zip(list1, list2, (a, b) => a + b) .Subscribe(x => Debug.Log(x)); // A1, B2, C3, D4, E5
Subject
外部から任意のタイミングでOnNext、OnComplete、OnErrorを送ることが可能です。
using UniRx; var subject = new Subject<int>(); subject.Subscribe(x => Debug.Log(x)); subject.OnNext(1); subject.OnNext(2); subject.OnNext(3); // 1, 2, 3
BehaviorSubject
Subjectとの違いは初期値の有無です。
using UniRx; var subject = new BehaviorSubject<int>(5); subject.Subscribe(x => Debug.Log(x)); subject.OnNext(1); subject.OnNext(2); subject.OnNext(3); // 5, 1, 2, 3
終わりに
オペレータはこの他にもたくさんありますので、使い方などの詳しい情報はUniRxのリポジトリやwikiをみると良いでしょう。それでは良いUniRxライフを。