UniRx_UniTask_学习记录_3.1_Subject

Observable 的制作方法

3.1 Subject

3.1.1 Subject

​ Subject 是观察者模式的核心,Subject继承了IObserver 和IObservable,可以记录所有订阅(Subscribe())的Observer,并同时发送消息(boardCast)

using UniRx;
using UnityEngine;

namespace Sample.Section3.Subjects
{
    public class SubjectSample : MonoBehaviour
    {
        private void Start()
        {
            var subject = new Subject<int>();
            //发送消息
            subject.OnNext(1);
            //订阅
            subject.Subscribe(
                x => Debug.Log("OnNext:" + x),
                ex => Debug.LogError("OnError:" + ex),
                () => Debug.Log("OnCompleted"));
            //发送消息
            subject.OnNext(2);
            subject.OnNext(3);
            subject.OnCompleted();
            // Dispose()
            subject.Dispose();
            
            /*
                OnNext:2
                OnNext:3
                OnCompleted
             */
        }
    }
}

​ 无法收到订阅前发送的消息

3.1.2 BehaviorSubject

​ BehaviorSubject 会缓存上一个消息,在新的Subscribe()的时候会发送这个消息,因为Subscribe()的时候需要一个过去的值,所以必须要有初期值。

using System;
using UniRx;
using UnityEngine;

namespace Sample.Section3.Subjects
{
    public class BehaviorSubjectSample : MonoBehaviour
    {
        private void Start()
        {
            
            // BehaviorSubject 要有初期值
            var behaviorSubject = new BehaviorSubject<int>(0);
            //发送消息
            behaviorSubject.OnNext(1);
            //订阅
            behaviorSubject.Subscribe(
                x => Debug.Log("OnNext:" + x),
                ex => Debug.LogError("OnError:" + ex),
                () => Debug.Log("OnCompleted"));
            //发送消息
            behaviorSubject.OnNext(2);
            // 打印暂存的值 和 现在的值比较
            Debug.Log("Last Value:" + behaviorSubject.Value);
            behaviorSubject.OnNext(3);
            behaviorSubject.OnCompleted();
            // Dispose
            behaviorSubject.Dispose();
            
            /*
             * OnNext:1
               OnNext:2
               Last Value:2
               OnNext:3
               OnCompleted
             */
        }
    }
}

​ 和Subject 不同的是可以接受 订阅前的发送的消息

3.1.3 ReplaySubject

​ ReplaySubject 是BehaviorSubject 的高级版,同样是缓存已发行的消息,可以对缓存的消息进行更细致的设定

//构造函数
public ReplaySubject()
public ReplaySubject(IScheduler scheduler)
public ReplaySubject(int bufferSize)
public ReplaySubject(
int bufferSize,
IScheduler scheduler)
public ReplaySubject(TimeSpan window)
public ReplaySubject(
TimeSpan window,
IScheduler scheduler)
public ReplaySubject(
int bufferSize,
TimeSpan window,
IScheduler scheduler)
int bufferSize可以缓存几个消息
TimeSpan window可以缓存多久的时间内的消息
IScheduler scheduler可以缓存多久的时间内的消息 在哪个线程上执行 默认是 CurrentThreadScheduler

ReplaySubject 和 BehaviorSubject的不同是 它会缓存OnError 和 OnCompleted

using UniRx;
using UnityEngine;

namespace Sample.Section3.Subjects
{
    public class ReplaySubjectSample : MonoBehaviour
    {
        private void Start()
        {
            // ReplaySubject 缓存过去的3个消息
            var subject = new ReplaySubject<int>(bufferSize: 3);
            // 发送消息
            for (int i = 0; i < 10; i++)
            {
                subject.OnNext(i);
            }
            // OnCompleted 也会被缓存
            subject.OnCompleted();
            // OnError 也会被缓存
            // subject.OnError(new Exception("Error!"));
            // 订阅
            subject.Subscribe(
                x => Debug.Log("OnNext:" + x),
                ex => Debug.LogError("OnError:" + ex),
                () => Debug.Log("OnCompleted"));
            subject.Dispose();
            
            /*
                OnNext:7
                OnNext:8
                OnNext:9
                OnCompleted
             */
        }
    }
}

​ OnCompleted 消息发行后 Subscribe() 也可以接受之前发送的消息

3.1.4 AsyncSubject

​ AsyncSubject 用来做异步处理的Subject,和TaskCompletionSource 相似

​ AsyncSubject在OnCompleted调用之前 不会输出结果,调用OnCompleted后才会发送最后一个OnNext消息

​ AsyncSubject最大的特点是不用管说明时候订阅,只要确定了结果,一定会收到消息。

​ 使用例

​ 在Unity比较常见的就是异步加载资源,在别的脚本里使用,但无法判断脚本的执行顺序,当然可以使用Unity的Script Execution Order ,但很不方便,也不推荐使用。这时候可以使用AsyncSubject

using System;
using System.Collections;
using UniRx;
using UnityEngine;

namespace Sample.Section3.Subjects.Async
{
    //游戏资源的读取
    public class GameResourceProvider : MonoBehaviour
    {
        //Player Texture 管理
        private readonly AsyncSubject<Texture> _playerTextureAsyncSubject = new AsyncSubject<Texture>();

        //外部调用
        public IObservable<Texture> PlayerTextureAsync => _playerTextureAsyncSubject;

        private void Start()
        {
            //启动时加载资源
            StartCoroutine(LoadTexture());
        }

        private IEnumerator LoadTexture()
        {
            // 异步加载图片
            var resource = Resources.LoadAsync<Texture>("Textures/player");
            yield return resource;
            // 读取完后再发送消息
            _playerTextureAsyncSubject.OnNext(resource.asset as Texture);
            _playerTextureAsyncSubject.OnCompleted();
        }
    }
}

using UniRx;
using UnityEngine;

namespace Sample.Section3.Subjects.Async
{
    //玩家图片变更
    public class PlayerTextureChanger : MonoBehaviour
    {
        [SerializeField]
        private GameResourceProvider _gameResourceProvider;
        private void Start()
        {
            // 当玩家图片加载完后再 设定玩家图片
            _gameResourceProvider.PlayerTextureAsync
                .Subscribe(SetMyTexture)
                .AddTo(this);
        }
        private void SetMyTexture(Texture newTexture)
        {
            var r = GetComponent<Renderer>();
            r.sharedMaterial.mainTexture = newTexture;
        }
    }
    
}

​ 这样不管脚本执行顺序如何都能确保PlayerTextureChanger.SetMyTexture()在GameResourceProvider.Start()之后执行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值