【UniRx】時間系のオペレータ #100
前回の成果
メッセージを変換するオペレータについて学んだ。
今回やること
今回は時間系のオペレータについてまとめます。
- 前回の成果
- 今回やること
- 一定時間後にメッセージを発行したい
- 一定時間後、一定間隔でメッセージを発行したい
- Interval
- 値の発行を遅れさせたい
- 最後のOnNextから一定時間OnNextが発行されない場合、OnErrorを発行したい
- 一定時間値が発行されない場合、最後の値を流す
- 値が来たら発行し、一定時間は発行しない
- 一定間隔でメッセージを発行する
- 次のフレームで処理をする
- 参考サイト様
一定時間後にメッセージを発行したい
Timer
引数で指定した時間経過後に、メッセージを発行することができます。
フレームを指定するTimerFrameも存在します。
一定時間後にメッセージを発行
/// <summary> /// 一定時間後にメッセージを発行 /// </summary> private void ExcuteTimer() { Observable .Timer(TimeSpan.FromSeconds(1)) .Subscribe(x => { Debug.Log("Timer OnNext : " + x); }, () => { Debug.Log("Timer OnCompleted"); }); }
結果
引数で指定した1秒が経過した後にメッセージが発行されます。
一定時間後、一定間隔でメッセージを発行したい
Timer
Timerの第二引数で次の値の発行の間隔を指定できます。
フレームを指定するTimerFrameも同様に、第二引数で次の値の発行の間隔を指定できます。
一定時間後に、一定間隔でメッセージを発行
/// <summary> /// 一定時間後に、一定間隔でメッセージを発行 /// 発行開始と発行間隔は異なる値で指定できる /// </summary> private void ExcuteTimerArgument() { TimeSpan timeSpan = TimeSpan.FromSeconds(1); Observable .Timer(timeSpan, timeSpan) .Subscribe(x => { // xは0からカウントされるlong型が入る Debug.Log("TimerArgument OnNext : " + x); }, () => { Debug.Log("TimerArgument OnCompleted"); }); }
結果
第一引数で指定した1秒後に最初のメッセージが発行されます。
第二引数で指定した1秒間隔でメッセージが発行され続けます。
Interval
こちらも同様に引数で、次の値の発行の間隔を指定できます。
Timerとの違いは経過時間と間隔が同様の値で扱われることになります。
定義は以下となっており、どちらもTimerObservableを生成しています。
/// <summary> /// Intervalの定義 /// </summary> public static IObservable<long> Interval(TimeSpan period) { return new TimerObservable(period, period, Scheduler.DefaultSchedulers.TimeBasedOperations); } /// <summary> /// Timerの定義 /// </summary> public static IObservable<long> Timer(TimeSpan dueTime, TimeSpan period) { return new TimerObservable(dueTime, period, Scheduler.DefaultSchedulers.TimeBasedOperations); }
IntervalはTimerObservableの第一引数、第二引数に同じ値を入れており、
Timerの場合は違う値を入れています。
一定時間後に、一定間隔でメッセージを発行
/// <summary> /// 一定時間後に、一定間隔でメッセージを発行 /// 発行開始と発行間隔はイコール /// </summary> private void ExcuteInterval() { Observable .Interval(TimeSpan.FromSeconds(1)) .Subscribe(x => { Debug.Log("Interval OnNext : " + x); }, () => { Debug.Log("Interval OnCompleted"); }); }
結果
引数で指定した1秒後に最初のメッセージが発行され、1秒間隔でメッセージが発行され続けます。
値の発行を遅れさせたい
Delay
引数に指定した時間、値の発行を遅延できます。
フレームを指定するDelayFrameも存在します。
メッセージの発行を遅延させる
/// <summary> /// メッセージの発行を遅延させる /// </summary> private void ExcuteDelay() { Observable .Range(0, 1) .Do(x => { Debug.Log("Range Call"); }) .Delay(TimeSpan.FromSeconds(1)) .Subscribe(x => { Debug.Log("Delay OnNext"); }, () => { Debug.Log("Delay OnCompleted"); }); }
結果
まず、Doで呼んでいる"Range Call"が発行されます。
その後、Delayの引数で指定した1秒後にメッセージが発行されます。
最後のOnNextから一定時間OnNextが発行されない場合、OnErrorを発行したい
Timeout
OnNextを発行してから、引数で指定した時間以内にOnNextが発行されない場合に、OnErrorを発行します。
一定時間値が発行されなかったら、onErrorを発行する
/// <summary> /// 一定時間値が発行されなかったら、onErrorを発行する /// </summary> private void ExcuteTimeout() { // キーが押されたらメッセージ発行 IObservable<Unit> input = this.UpdateAsObservable() .Where(_ => Input.anyKeyDown); Observable .Timeout(input, TimeSpan.FromSeconds(3)) .Subscribe(x => { Debug.Log("Timeout OnNext"); }, err => { Debug.Log("Timeout OnError"); }, () => { Debug.Log("Timeout OnCompleted"); }); }
結果
何かキーが押されたらOnNextを発行します。
キーを押してから引数で指定している3秒以内にキーが押されないとOnErrorが発行されます。
一定時間値が発行されない場合、最後の値を流す
Throttle
引数に指定した時間、値が発行されないと最後の値を発行します。
その間に流れてきた値は全て無視されます。
フレームを指定するThrottleFrameも存在します。
一定時間値が発行されなかったら、最後の値を流す
/// <summary> /// 一定時間値が発行されなかったら、最後の値を流す /// </summary> private void ExcuteThrottle() { // キーが押されたらメッセージ発行 IObservable<Unit> input = this.UpdateAsObservable() .Where(_ => Input.anyKeyDown); Observable .Throttle(input, TimeSpan.FromSeconds(3)) .Subscribe(x => { Debug.Log("Throttle OnNext"); }, () => { Debug.Log("Throttle OnCompleted"); }); }
結果
キーが押されてから、引数で指定した3秒間キーが押されないとOnNextが発行されます。
値が来たら発行し、一定時間は発行しない
ThrottleFirst
最初に値が来たらその値を流し、引数に指定した時間は値の発行を無視します。
フレームを指定するThrottleFirstFrameもあります。
似たオペレータにSampleがありますが、こちらは最初の値を発行します。
最初は値を発行し、一定時間発行をしない
/// <summary> /// 最初は値を発行し、一定時間発行をしない /// Sampleとの違いは、最初の値を発行する /// </summary> private void ExcuteThrottleFirst() { // キーが押されたらメッセージ発行 IObservable<Unit> input = this.UpdateAsObservable() .Where(_ => Input.anyKeyDown); Observable .ThrottleFirst(input, TimeSpan.FromSeconds(3)) .Subscribe(x => { Debug.Log("ThrottleFirst OnNext"); }, () => { Debug.Log("ThrottleFirst OnCompleted"); }); }
結果
キーが押されるとOnNextが発行されます。
しかしその後、3秒間はキーを押してもOnNextは発行されません。
一定間隔でメッセージを発行する
Sample
引数で指定した間隔で、メッセージが流れてきたら発行します。
似たオペレータThrottleFirstがありますが、こちらは最後の値を発行します。
一定間隔でメッセージを発行
/// <summary> /// 一定間隔でメッセージを発行 /// ThrottleFirstとの違いは最後の値を発行する /// </summary> private void ExcuteSample() { // 1フレーム毎にメッセージを発行 IObservable<long> inteval = Observable.IntervalFrame(1); Observable .Sample(inteval, TimeSpan.FromSeconds(1)) .Subscribe(x => { Debug.Log("Sample OnNext"); }, () => { Debug.Log("Sample OnCompleted"); }); }
結果
intervalストリームにより、1フレーム毎にメッセージを発行しようとしています。
しかし、Sampleで1秒毎に指定しているので、1秒毎にOnNextが発行されます。
次のフレームで処理をする
NextFrame
処理を1フレーム遅延させることができます。
次のフレームで処理をする
/// <summary> /// 次のフレームで処理をする /// </summary> private void ExcuteNextFrame() { Observable .NextFrame() .Subscribe(x => { Debug.Log("NextFrame OnNext"); }, () => { Debug.Log("NextFrame OnCompleted"); }); }
結果
1フレーム後にOnNextが発行されます。
今回は以上となります。
ここまでご視聴ありがとうございました。