文章目录
3.3 Factory Method
Factory Method 是 Observable 生成 Observable的 静态方法,有很多种Factory Method,不需要准备 Subject就可以生成Observable。
Factory Method 每次 Subscribe()时 都生成Observable, 生成的Observable 都是 Cold Observable
3.3.1 Observable.Return
Observable.Return 会发送一次 OnNext 和 OnCompleted 消息
public static IObservable<T> Return<T>(T value)
public static IObservable<T> Return<T>(
T value,
IScheduler scheduler)
使用例
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class ReturnSample : MonoBehaviour
{
private void Start()
{
Observable.Return(100)
.Subscribe(
x => Debug.Log("OnNext:" + x),
ex => Debug.LogError("OnError:" + ex.Message),
() => Debug.Log("OnCompleted")
);
}
}
}
3.3.2 Observable.Range
Observable.Range 从 整数 start 开始,count 数 增加,最后 发行OnCompleted
public static IObservable<int> Range(
int start,
int count)
public static IObservable<int> Range(
int start,
int count,
IScheduler scheduler)
使用例
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class RangeSample : MonoBehaviour
{
private void Start()
{
// 从0 开始 发送5个 连续增加 的消息
Observable.Range(start: 0, count: 5)
.Subscribe(
x => Debug.Log("OnNext:" + x),
ex => Debug.LogError("OnError:" + ex.Message),
() => Debug.Log("OnCompleted")
);
}
}
}
3.3.3 Observable.Repeat
Observable.Repeat 把 OnNext Message 重复发送 repeatCount 个,最后发送OnCompleted消息
public static IObservable<T> Repeat<T>(T value)
public static IObservable<T> Repeat<T>(
T value,
IScheduler scheduler)
public static IObservable<T> Repeat<T>(
T value,
int repeatCount)
public static IObservable<T> Repeat<T>(
T value,
int repeatCount,
IScheduler scheduler)
使用例
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class RepeatSample : MonoBehaviour
{
private void Start()
{
// 发送3个 "yes"
Observable.Repeat(value: "yes", repeatCount: 3)
.Subscribe(
x => Debug.Log("OnNext:" + x),
ex => Debug.LogError("OnError:" + ex.Message),
() => Debug.Log("OnCompleted")
);
}
}
}
3.3.4 Observable.Throw
Observable.Throw 发送 OnError Message
public static IObservable<T> Throw<T>(Exception error)
public static IObservable<T> Throw<T>(
Exception error,
T witness)
public static IObservable<T> Throw<T>(
Exception error,
IScheduler scheduler)
public static IObservable<T> Throw<T>(
Exception error,
IScheduler scheduler,
T witness)
使用例
using System;
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class ThrowSample : MonoBehaviour
{
private void Start()
{
// int を扱うObservable からOnError メッセージを発行する
Observable.Throw<int>(new Exception("发生错误"))
.Subscribe(
x => Debug.Log("OnNext:" + x),
ex => Debug.LogError("OnError:" + ex.Message),
() => Debug.Log("OnCompleted")
);
}
}
}
3.3.5 Observable.Empty
Observable.Empty发送 OnComplete Message
public static IObservable<T> Empty<T>()
public static IObservable<T> Empty<T>(IScheduler scheduler)
public static IObservable<T> Empty<T>(T witness)
public static IObservable<T> Empty<T>(
IScheduler scheduler,
T witness)
使用例
using System;
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class EmptySample : MonoBehaviour
{
private void Start()
{
Observable.Empty<int>()
.Subscribe(
x => Debug.Log("OnNext:" + x),
ex => Debug.LogError("OnError:" + ex.Message),
() => Debug.Log("OnCompleted")
);
}
}
}
3.3.6 Observable.Never
Observable.Never 什么消息都不发送
public static IObservable<T> Never<T>()
public static IObservable<T> Never<T>(T witness)
使用例
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class NeverSample : MonoBehaviour
{
private void Start()
{
Observable.Never<int>()
.Subscribe(
x => Debug.Log("OnNext:" + x),
ex => Debug.LogError("OnError:" + ex.Message),
() => Debug.Log("OnCompleted")
);
}
}
}
3.3.7 Observable.Defer
Observable.Defer 在 Subscribe()时 执行delegate 生成新的 Observable
Observable.Defer 可以对 Observable 生成时 Subcribe() 时机 进行一定程度 的调控
public static IObservable<T> Defer<T>(Func<IObservable<T>> observableFactory)
使用例
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class DeferSample : MonoBehaviour
{
private void Start()
{
//在 Subscribe() 时生成 「返回随机数的Observable」
var rand = Observable.Defer(() =>
{
// 随机数
var randomValue = UnityEngine.Random.Range(0, 100);
// 返回随机数的 Observable
return Observable.Return(randomValue);
});
// 复数回 Subscribe
rand.Subscribe(x => Debug.Log(x));
rand.Subscribe(x => Debug.Log(x));
rand.Subscribe(x => Debug.Log(x));
}
}
}
3.3.8 IEnumerable.ToObservable
IEnumerable.ToObservable 是 IEnumerable 的扩张 方法, iterator 的值 顺便 变换成 Observable
public static IObservable<T> ToObservable<T>(this IEnumerable<T> source)
public static IObservable<T> ToObservable<T>(
this IEnumerable<T> source,
IScheduler scheduler)
使用例
using System;
using UnityEngine;
using UniRx;
namespace Sample.Section3.FactoryMethods
{
public class ToObservableSample : MonoBehaviour
{
private void Start()
{
// 数组
string[] strArray = new[] { "apple", "banana", "lemon" };
// 数组 变成 Observable 并顺序发送消息
strArray.ToObservable()
.Subscribe(
x => Debug.Log("OnNext:" + x),
ex => Debug.LogError("OnError:" + ex.Message),
() => Debug.Log("OnCompleted"));
}
}
}
使用 MainThreadScheduler
像 IEnumerable.ToObservable, Observable.Range 都会 连续发行OnNext 消息的 工厂方法,如果指定Scheduler为MainThreadScheduler,发行消息 会 1frame 1个消息
**使用例 **
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class WithMainThreadSchedulerSample : MonoBehaviour
{
private void Start()
{
//指定 MainThreadScheduler
Observable.Range(
start: 0,
count: 5,
scheduler: Scheduler.MainThread
).Subscribe(x =>
{
//表示 当前的Frame
Debug.Log($"frame:{Time.frameCount} value:{x}");
});
}
}
}
**比较 如果使用CurrentThread Scheduler **
using System;
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class WithCurrentThreadSchedulerSample : MonoBehaviour
{
private void Start()
{
// 指定 CurrentThreadScheduler
Observable.Range(
start: 0,
count: 5,
scheduler: Scheduler.CurrentThread
).Subscribe(x =>
{
// 表示当前 Frame
Debug.Log($"frame:{Time.frameCount} value:{x}");
});
}
}
}
使用CurrentThread Scheduler 则会在 同一Frame 里 发送 所有消息
3.3.9 Observable.Create
Observable.Create 可以在 任意时机自由的 生成 Observable
public static IObservable<T> Create<T>(Func<IObserver<T>, IDisposable> subscribe)
public static IObservable<T> Create<T>(
Func<IObserver<T>, IDisposable> subscribe,
bool isRequiredSubscribeOnCurrentThread)
使用例
使用Observable.Create 对任意形式的 非同期处理 变换成 Observable
using System;
using System.Threading.Tasks;
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class CreateSample : MonoBehaviour
{
private void Start()
{
// 从 A 开始 顺序生成 字母
var observable = Observable.Create<char>(observer =>
{
// 带有 IDisposable 和 CancellationToken的 Object
// Dispose() 时 出去 Cancel状态
var disposable = new CancellationDisposable();
// 线程池上执行
Task.Run(async () =>
{
// 发行 'A' - 'Z'
for (var i = 0; i < 26; i++)
{
// 等待 1秒
await Task.Delay(TimeSpan.FromSeconds(1), disposable.Token);
// 发行 文字
observer.OnNext((char) ('A' + i));
}
// 发行完了 发送 OnCompleted
observer.OnCompleted();
}, disposable.Token);
// Subscribe()中断的同时
// CancellationToken 已经是Canel状态了
return disposable;
});
// 订阅
observable.Subscribe(
x => Debug.Log("OnNext:" + x),
ex => Debug.LogError("OnError:" + ex.Message),
() => Debug.Log("OnCompleted")
).AddTo(this);
}
}
}
3.3.10 Observable.CreateWithState<T, TState>
C# 的 Lambda表达式中的 引用局部变量,内部堆里会分配内存,会变为垃圾回收的对象,所以使用Lambda表达式时防止使用局部变量是很重要的
Observable.CreateWithState<T, TState>和Observable.Create<T, TState> 几乎一样,但可以防止上面情况的出现。
public static IObservable<T> CreateWithState<T, TState>(
TState state,
Func<TState, IObserver<T>, IDisposable> subscribe)
public static IObservable<T> CreateWithState<T, TState>(
TState state,
Func<TState, IObserver<T>, IDisposable> subscribe,
bool isRequiredSubscribeOnCurrentThread)
使用例
using System;
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class CreateWithStateSample : MonoBehaviour
{
private void Start()
{
CreateCountObservable(10).Subscribe(x => Debug.Log(x));
}
// 返回指定个数的连续值的Observable
private IObservable<int> CreateCountObservable(int count)
{
// count 为 0 时 发送OnCompleted
if (count <= 0) return Observable.Empty<int>();
// 指定的数值 连续 发送
return Observable.CreateWithState<int, int>(
state: count,
subscribe: (maxCount, observer) =>
{
// maxCount 为 State 指定的值
for (int i = 0; i < maxCount; i++)
{
observer.OnNext(maxCount);
}
observer.OnCompleted();
return Disposable.Empty;
});
}
}
}
3.3.11 Observable.CreateSafe
Observable.CreateSafe 当OnNext例外发生时 会自动停止的Observable
Observable.Create 当OnNext例外发生时 会继续运作
因此Observable.Create 适合Hot Observable
Observable.CreateSafe适合Cold Observable
public static IObservable<T> CreateSafe<T>(Func<IObserver<T>, IDisposable> subscribe)
public static IObservable<T> CreateSafe<T>(
Func<IObserver<T>, IDisposable> subscribe,
bool isRequiredSubscribeOnCurrentThread)
3.3.12 Observable.FromEvent/Observable.FromEventPattern
Observable.FromEvent/Observable.FromEventPattern 可以把 C# 的标准Event 和 Unity 的Unity Event 转换为 Observable
Unity 基本上只会使用Observable.FromEvent
使用例
using System;
using UniRx;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
namespace Sample.Section3.FactoryMethods
{
public class FromEventSample : MonoBehaviour
{
// 原始时间
public sealed class MyEventArgs : EventArgs
{
public int MyProperty { get; set; }
}
// MyEventArgs Handler
event EventHandler<MyEventArgs> _onEvent;
// Int Action
event Action<int> _callBackAction;
// uGUI Button
[SerializeField] private Button _uiButton;
private readonly CompositeDisposable _disposables = new CompositeDisposable();
private void Start()
{
// FromEventPattern
// (sender, eventArgs)を両方使ってイベントをIObservable<MyEventArgs>に変換する
Observable.FromEventPattern<EventHandler<MyEventArgs>, MyEventArgs>(
h => h.Invoke,
h => _onEvent += h,
h => _onEvent -= h)
.Subscribe()
.AddTo(_disposables);
// FromEvent
// eventArgs => IObservable<MyEventArgs>
Observable.FromEvent<EventHandler<MyEventArgs>, MyEventArgs>(
h => (sender, e) => h(e),
h => _onEvent += h,
h => _onEvent -= h)
.Subscribe()
.AddTo(_disposables);
// Action<T> => Observable<T>
Observable.FromEvent<int>(
h => _callBackAction += h,
h => _callBackAction -= h)
.Subscribe()
.AddTo(_disposables);
// UnityEvent => Observable
Observable.FromEvent<UnityAction>(
h => new UnityAction(h),
h => _uiButton.onClick.AddListener(h),
h => _uiButton.onClick.RemoveListener(h)
).Subscribe()
.AddTo(_disposables);
// UnityEvent 变换成 Observable 的简单语法
_uiButton.onClick.AsObservable().Subscribe().AddTo(_disposables);
}
private void OnDestroy()
{
// 销毁的时候 Dispose
_disposables.Dispose();
}
}
}
3.3.13 Observable.Timer
Observable.Timer 在指定时间后,生成Observable,发送一个OnNext消息,然后OnCompleted
public static IObservable<long> Timer(TimeSpan dueTime)
public static IObservable<long> Timer(
TimeSpan dueTime,
IScheduler scheduler)
使用例
using System;
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class TimerSample1 : MonoBehaviour
{
private void Start()
{
// 一秒后 发送
var timer = Observable.Timer(dueTime: TimeSpan.FromSeconds(1));
Debug.Log("Subscribe 时刻:" + Time.time);
timer.Subscribe(x =>
{
Debug.Log("OnNext 发送时刻:" + Time.time);
Debug.Log("OnNext 里面:" + x);
}, () => Debug.Log("OnCompleted"));
}
}
}
**指定两个 TimeSpan **
最初一段时间待机,然后反复发送消息的间隔,
dueTime 最初的待机时间
period 反复发送消息的间隔
不会发送OnCompleted消息,需要手动 Disposed()
public static IObservable<long> Timer(
TimeSpan dueTime,
TimeSpan period)
public static IObservable<long> Timer(
TimeSpan dueTime,
TimeSpan period,
IScheduler scheduler)
使用例
using System;
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class TimerSample2 : MonoBehaviour
{
private void Start()
{
// 等1s 每0.5s 发送一次消息
var timer = Observable.Timer(
dueTime: TimeSpan.FromSeconds(1),
period: TimeSpan.FromSeconds(0.5));
Debug.Log("Subscribe 的时间:" + Time.time);
timer.Subscribe(
x => Debug.Log($"[{x}]:{Time.time}"),
() => Debug.Log("OnCompleted")
)
//GameObject 被销毁前 会无限Loop
.AddTo(this); // Dispose()の実行を忘れない
}
}
}
指定DateTimeOffset
指定时刻的时候发行消息
public static IObservable<long> Timer(DateTimeOffset dueTime)
public static IObservable<long> Timer(
DateTimeOffset dueTime,
IScheduler scheduler)
public static IObservable<long> Timer(
DateTimeOffset dueTime,
TimeSpan period)
public static IObservable<long> Timer(
DateTimeOffset dueTime,
TimeSpan period,
IScheduler scheduler)
3.3.14 Observable.TimerFrame
Observable.TimerFrame 和 Observable.Timer使用方法基本一样,只是不是TImeSpan而是 Unity的Frame数
可以指定 FrameCountType
**只指定 dueTimeFrameCount **
public static IObservable<long> TimerFrame(
int dueTimeFrameCount,
FrameCountType frameCountType = FrameCountType.Update)
使用例
using System;
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class TimerFrameSample : MonoBehaviour
{
private void Start()
{
var timer = Observable.TimerFrame(dueTimeFrameCount: 5);
Debug.Log("Subscribe() 时的Frame :" + Time.frameCount);
timer.Subscribe(x =>
{
Debug.Log("OnNext 时的Frame:" + Time.frameCount);
Debug.Log("OnNext :" + x);
}, () => Debug.Log("OnCompleted"));
}
}
}
**指定 dueTimeFrameCount 和 periodFrameCount **
和TImer 一样
使用例
using System;
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class TimerFrameSample2 : MonoBehaviour
{
private void Start()
{
var timer = Observable.TimerFrame(dueTimeFrameCount: 5, periodFrameCount: 10);
Debug.Log("Subscribe() 时的Frame :" + Time.frameCount);
timer.Subscribe(
x => Debug.Log($"{x} - {Time.frameCount}"),
() => Debug.Log("OnCompleted")
).AddTo(this); // 不要忘记Dispose()
}
}
}
3.3.15 Observable.Interval
Observable.Interval 和 Observable.Timer 相似,不同的时Observable.Interval 只能指定 period,Subscribe()时 间隔period 时间发送消息
需要手动停止
public static IObservable<long> Interval(TimeSpan period)
public static IObservable<long> Interval(
TimeSpan period,
IScheduler scheduler)
使用例
using System;
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class IntervalSample : MonoBehaviour
{
private void Start()
{
// Interval
// Subscribe()后等待1s发送消息
// (等待1s、然后每隔1s 发送消息)
Observable.Interval(TimeSpan.FromSeconds(1))
.Subscribe()
.AddTo(this); // GameObject 销毁时 Dispose()
// 比较 Observable.Timer
// Subscribe() 时立刻发送消息、然后每隔1s 发送消息
Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(1))
.Subscribe()
.AddTo(this); // GameObject 销毁时 Dispose()
}
}
}
3.3.16 Observable.IntervalFrame
Observable.IntervalFrame 是 Observable.Interval 的 Frame版,基本使用一样
public static IObservable<long> IntervalFrame(
int intervalFrameCount,
FrameCountType frameCountType = FrameCountType.Update)
3.3.17 Observable.FromAsyncPattern
Observable.FromAsyncPattern 把异步执行的委托 ,将结果转换成 Observable
通过指定委托的参数BeginInvoke 和 EndInvoke,委托的异步执行可以被转换为可由Observable处理的模式
不能指定Scheduler
使用例
using System;
using System.IO;
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class FromAsyncPatternSample : MonoBehaviour
{
private void Start()
{
// 指定文件名,读取后返回结果的 委托
Func<string, string> readFile = fileName =>
{
using (var r = new StreamReader(fileName))
{
return r.ReadToEnd();
}
};
// 委托进行异步处理,并把结果作为Observable
// 返回值也是委托
Func<string, IObservable<string>> f =
Observable.FromAsyncPattern<string, string>(
readFile.BeginInvoke,
readFile.EndInvoke);
// 委托执行时 异步开始
// 内部使用的是 AsyncSubject
IObservable<string> readAsync = f("data.txt");
// 订阅结果
readAsync.Subscribe(x => Debug.Log(x));
}
}
}
3.3.18 Observable.ToAsync
Observable.ToAsync 是 Observable.FromAsyncPattern 的简略版
将指定的委托异步执行,并将结果转换为Observable
异步处理是在指定的Scheduler上执行的。
该工厂方法返回一个委托(Func<IObservable>)作为返回值。 这
异步处理在委托被明确执行的时机开始执行。
**指定 Func **
public static Func<IObservable<T>> ToAsync<T>(Func<T> function)
public static Func<IObservable<T>> ToAsync<T>(
Func<T> function,
IScheduler scheduler)
指定 Action
// Action 是 变成 IObservable<Unit>
public static Func<IObservable<Unit>> ToAsync(Action action)
public static Func<IObservable<Unit>> ToAsync(Action action, IScheduler scheduler)
使用例
using System;
using System.IO;
using UniRx;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class ToAsyncSample1 : MonoBehaviour
{
private void Start()
{
// Observable.ToAsync 的返回值 Func<IObservable<T>>
Func<IObservable<string>> fileReadFunc;
// mainthread 上读取文件
fileReadFunc = Observable.ToAsync(() =>
{
using (var r = new StreamReader(@"data.txt"))
{
// 读取的结果 用Observable
return r.ReadToEnd();
}
}, Scheduler.ThreadPool);
// 调用才能订阅
fileReadFunc().Subscribe(x => Debug.Log(x));
// Invoke()也行
// fileReadFunc.Invoke().Subscribe();
}
}
}
3.3.19 Observable.Start
Observable.Start 是 Observable.ToAsync 的简略版
Observable.ToAsync 需要调用委托才嗯那个订阅,Observable.Start可以直接订阅
如果在订阅时 就执行委托的话,用这个比较方便
使用例
using System;
using System.IO;
using UniRx;
using Unity.VisualScripting;
using UnityEngine;
namespace Sample.Section3.FactoryMethods
{
public class StartSample : MonoBehaviour
{
private void Start()
{
// Observable.Start<T>的返回值 是 IObservable<T>
Observable.Start(() =>
{
// 读取文件
using (var r = new StreamReader(@"data.txt"))
{
// 读取的结果用Observable
return r.ReadToEnd();
}
}, Scheduler.ThreadPool)
.Subscribe(x => Debug.Log(x)); // Start()的返回值可以 直接Subscribe
}
}
}
3.3.20 ObservableWWW
ObservableWWW是一种使用Unity的WWW掩盖HTTP通信的方法,这样它就可以被当作Observable来处理。
通过使用ObservableWWW,可以实现HTTP通信,而不需要自己定义coroutines。
使用例
using UniRx;
using UnityEngine;
// Unity 2018.3之前 可以使用
namespace Sample.Section3.FactoryMethods
{
public class ObservableWWWSample : MonoBehaviour
{
private void Start()
{
var uri = "https://unity3d.com";
// 只接受文字结果
ObservableWWW.Get(uri)
.Subscribe(x => Debug.Log(x));
// 通信结束时接受 www
ObservableWWW.GetWWW(uri)
.Subscribe(www => Debug.Log(www.text));
}
}
}
使用UnityWebRequest
Unity2018.3 废除了WWW,之后的版本用UnityWebRequest
UniRx 并没有提供UnityWebRequest的Observableb的变换功能,但在2018.3 可以使用async/await 和 Unitask
使用例
using UniRx;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
namespace Sample.Section3.FactoryMethods
{
public class UnityWebRequestToObservable : MonoBehaviour
{
private void Start()
{
// UniTask => Observable
FetchAsync("http://www.baidu.com/")
.ToObservable()
.Subscribe(x => Debug.Log(x));
}
// 用 UnityWebRequest 进行HTTP通信
private async UniTask<string> FetchAsync(string uri)
{
using (var uwr = UnityWebRequest.Get(uri))
{
// UniTask 可以 await
await uwr.SendWebRequest();
return uwr.downloadHandler.text;
}
}
}
}