UniRx之ReactiveCommand

news2024/11/17 16:39:37

前言

UniRx中ReactiveCommand和AsyncReactiveCommand是一种基于IObservable的可控命令机制,用于控制是否允许进程运行
很难用文字说明,下面我们直接看代码吧

ReactiveCommand

void Start()
{
    //创建IObservable<bool>
    ReactiveProperty<bool> gate = new BoolReactiveProperty(false);

    // 基于gate创建一个ReactiveCommand
    var command = new ReactiveCommand((IObservable<bool>)gate);

    // command.Execute()代表命令执行,在Subscribe回调中接受
    command.Subscribe(_ =>
    {
        Debug.Log("执行");
    });

    // 设置值为false,
    gate.Value = false;
    Debug.Log("gate = false ");

	//执行Execute时判定gate状态
	//如果为true,则在Observable上执行OnNext
	//如果是false的话什么都不做
    command.Execute();

    // 设置值为true
    gate.Value = true;
    Debug.Log("gate = true");

    command.Execute();
}

输出
gate = false
gate = true
执行

ReactiveCommand本身是一个可订阅的Sunscribe实体,并通过Execute()执行发布OnNext
ReactiveCommand以IObservable为参数,利用Observable的值来控制命令的执行权限
原理见下图:
当value为false时
在这里插入图片描述
当value为true时
在这里插入图片描述

ToReactiveCommand

IObservable直接通过ToReactiveCommand()创建ReactiveCommand,而无需 new ReactiveCommand。
如下所示,其他用法都一致。

ReactiveProperty<bool> gate = new BoolReactiveProperty(false);
var command = gate.ToReactiveCommand();

与UGUI结合

上面的示例虽然容易理解,但是没有任何实用价值,ReactiveCommand的真正价值在于和UGUI的联动。
看示例代码

public class ReactiveCommandSample : MonoBehaviour
{
    [SerializeField] private Toggle _toggle;
    [SerializeField] private Button _button;
    [SerializeField] private Text _resultText;

    void Start()
    {
        // 使用toggle状态创建ReactiveCommand
        var command = _toggle.OnValueChangedAsObservable().ToReactiveCommand();

        // 绑定到Button,通过toogle的值来控制button的interactive
        command.BindTo(_button);
        command.Subscribe(_ =>
        {
            _resultText.text += "Click!";
        });
		
        // BindToOnClick来定义
        // command.BindToOnClick(_button, _ => _resultText.text += "Click!");
    }
}

在这里插入图片描述
按钮的交互状态和点击事件都取决于toogle的开关状态

AsyncReactiveCommand

AsyncReactiveCommand是ReactiveCommand的异步版本。他们的行为相似,主要区别在于Subscribe函数结构

IDisposable Subscribe(Func<T, IObservable<Unit>> asyncAction);

AsyncReactiveCommand创建时,如果没有指定任何参数,它会在Execute()执行时自行将执行状态切换为false。
并且在订阅时等待IObservable完成,并在一切完成时返回 true 。

我们通过示例来看下:
以下代码对输入的 URL 执行 HTTP 通信并显示结果。
AsyncReactiveCommand使通信过程和Button的状态连接起来。

public class AsyncReactiveCommandSample : MonoBehaviour
{
    [SerializeField] private InputField _urlText;
    [SerializeField] private Button _button;
    [SerializeField] private Text _resultText;

    void Start()
    {
    	//创建空参AsyncReactiveCommand
        var command = new AsyncReactiveCommand();
		//和button回调绑定
        command.BindToOnClick(_button, _ =>
        {
        	//www是一个异步过程,异步请求的过程中,command的value都是false,直到请求返回,value为true
            return ObservableWWW.GetWWW(_urlText.text)
                    .ForEachAsync(www => _resultText.text = www.text);
        });
    }
}

在这里插入图片描述
在 HTTP 通信期间 Button 是灰色和禁用的。

通过使用AsyncReactiveCommand,我们可以轻松编写执行异步处理,直到完成才执行下一个命令。换句话说,我们能够创建一个准确的异步响应机制
如果一个运行多个AsyncReactiveCommand,即并行运行异步处理,则直到所有异步处理完成后,才会返回true状态。

AsyncReactiveCommand简写方式

使用简写方法,你会发现自己新建AsyncReactiveCommand是多余的。
UniRx提供了一个AsyncReactiveCommand简写方式来直接生成和使用UI 元素BindToOnClick。
代码如下:

//普通方式
var command = new AsyncReactiveCommand();
command.BindToOnClick(_button, _ =>
{
    return ObservableWWW.GetWWW(_urlText.text)
            .ForEachAsync(www => _resultText.text = www.text);
});

//简写方式
_button.BindToOnClick(_ =>
{
    return ObservableWWW.GetWWW(_urlText.text)
        .ForEachAsync(www => _resultText.text = www.text);
});

补充:ForEachAsync
ForEachAsync代表当有值流动时,它会转换为同时只处理一次 OnCompleted() 和 OnNext() 的 UnitObservable。或者可以理解为Do()+AsUnitObservable();

AsyncReactiveCommand控制用户界面

AsyncReactiveCommand也有接受IReactiveProperty参数的构造方法。
使用它,我们可以使用一个通用的 IReactiveProperty 控制多个 AsyncReactiveCommand。
代码如下:

public class AsyncReactiveCommandSample2 : MonoBehaviour
{
    [SerializeField] private Button _wait1SecondButton;
    [SerializeField] private Button _wait2SecondsButton;
    [SerializeField] private Button _httpButton;
    [SerializeField] private Text _resultText;

    /// <summary>
    /// 所有按钮都通用的ReactiveProperty
    /// </summary>
    private ReactiveProperty<bool> _sharedGate = new ReactiveProperty<bool>(true);

    void Start()
    {
        // 等待1秒的按钮
        _wait1SecondButton.BindToOnClick(_sharedGate, _ =>
        {
            _resultText.text = "等待1秒";
            return Observable.Timer(TimeSpan.FromSeconds(1))
                .ForEachAsync(__ => _resultText.text = "1秒钟过去了");
        });

        // 等待2秒的按钮
        _wait2SecondsButton.BindToOnClick(_sharedGate, _ =>
        {
            _resultText.text = "等待2秒";
            return Observable.Timer(TimeSpan.FromSeconds(2))
                .ForEachAsync(__ => _resultText.text = "2秒钟过去了");
        });

        // 通信按钮
        _httpButton.BindToOnClick(_sharedGate, _ =>
        {
            _resultText.text = "发起通信";
            return ObservableWWW.GetWWW("https://unity3d.com")
                .ForEachAsync(www => _resultText.text = www.text);
        });
    }
}

在这里插入图片描述
这样,通过将公共值传递给AsyncReactiveCommand ,现在IReactiveProperty可以对 Button 进行分组并共同管理它们的状态了。

总结

ReactiveCommand,AsyncReactiveCommand 是一个感觉用处不大,但其实通用性高,用起来非常方便的机制。尤其是当它绑定到UI上时,才真正显示出它的价值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/195452.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分布式事务2种协议 及 4种模式

分布式事务协议 解决分布式事务&#xff0c;也有相应的规范和协议。分布式事务相关的协议有2PC、3PC。 由于三阶段提交协议3PC非常难实现&#xff0c;目前市面主流的分布式事务解决方案都是2PC协议。 2PC&#xff1a;两阶段提交协议 两阶段提交协议&#xff1a;事务管理器分…

如何为客户创建一个简单好用的帮助文档?

产品售后服务难&#xff0c;客服人员压力大&#xff0c;客户不满意。相信这是很多企业都面临的问题&#xff0c;产品是卖出去了&#xff0c;但是做不完的售后&#xff0c;回答不完的重复问题&#xff0c;电话、微信响个不停&#xff0c;售后服务一直都是企业的一个痛点&#xf…

JSR303数据校验和@ControllerAdvice统一异常处理

1.引入依赖&#xff08;springboot2.3之后需要引入&#xff09; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId><version>2.6.6</version> </dependency>…

scrapy总结

一、scrapy是什么&#xff1f;*结构性数据&#xff1a;即同一类型的数据如&#xff1a;某一网页上的同一类型的标签二、scrapy安装pip install scrapy出错提示to update pip&#xff0c;请升级pippython -m pip install --upgrade pip三、scrapy的基本使用&#xff08;爬虫项目…

Python __del__()方法:销毁对象

Python 通过调用 __init__() 方法构造当前类的实例化对象&#xff0c;而本节要学的 __del__() 方法&#xff0c;功能正好和 __init__() 相反&#xff0c;其用来销毁实例化对象。事实上在编写程序时&#xff0c;如果之前创建的类实例化对象后续不再使用&#xff0c;最好在适当位…

Python爬虫-某懂车平台之汽车销量排行榜

前言 本文是该专栏的第33篇,后面会持续分享python爬虫干货知识,记得关注。 之前笔者在本专栏有详细介绍过该平台二手车数据,感兴趣的同学可以在本专栏往前翻阅查找。而本文要介绍的内容,是汽车销量排行数据。 地址:aHR0cHM6Ly93d3cuZG9uZ2NoZWRpLmNvbS9zYWxlcw== (注:地…

哪个牌子台灯对孩子视力好?精选不同价位的学生护眼台灯

在我国&#xff0c;由于科技水平的提高和电子产品的普及&#xff0c;儿童青少年的近视率正逐年攀升&#xff0c;且出现低龄化现象。2020年&#xff0c;我国儿童青少年总体近视率竟高达52.7%&#xff0c;其中6岁儿童已达14.3%&#xff0c;小学生为35.6%&#xff0c;初中生为71.1…

Hue(1): Apache Hue 介绍

1 Hue 是什么 HUEHadoop User Experience Hue 是一个开源的 Apache Hadoop UI 系统&#xff0c;由 Cloudera Desktop 演化而来&#xff0c;最后 Cloudera 公司将其贡献给 Apache 基金会的 Hadoop 社区&#xff0c;它是基于Python Web 框架 Django 实现的。 通过使用 Hue&am…

GAMES101笔记:BRDF和渲染方程

BRDF : 双向反射分布函数(Bidirectional Reflectance Distribution Function) 描述从某个方向入射的能量反射到不同的方向上的能量的分布。 理解反射 从能量的角度理解反射。上图中&#xff0c;ωi\omega_iωi​方向入射的光线具有的Radiance&#xff0c;累积在微小面积dAdAd…

沉浸式 3D 场景下的多视点视频 增强算法研究

沉浸式 3D 场景下的多视点视频 增强算法研究研究内容图像质量增强为什么进行图像质量增强图像有损压缩技术多视点视频中的深度图像特点视点数目增强虚拟视点合成技术视点外推为什么进行视点数目增强主要贡献基于自适应残差网络的多视点压缩深度图像增强算法基于多约束编解码网络…

SautinSoft PDF Focus .Net 8.6.1 Crack

PDF Focus .Net 完整的 API 可在 .NET 平台上转换任何 PDF 文档, .Net 程序集提供 API 以将 PDF 转换为所有格式&#xff1a;DOCX、RTF、HTML、XML、文本、Excel、.Net 和 C# 中的图像。 介绍 PDF Focus .Net 旨在帮助您开发需要转换任何 PDF 文档的应用程序。看看PDF Focus .N…

2023年“华数杯”国际大学生数学建模A题完整思路

2023华数杯如期开赛&#xff0c;本次比赛作为美赛的模拟赛&#xff0c;赛题和比赛时间都和美赛高度相似&#xff0c;因此大家 完全可以当作一次美赛之前的练习赛进行。美赛的发题时间与华数杯一致&#xff0c;都是早晨六点&#xff0c;现已经将机器翻译的初步翻译 结果进行了分…

C#里最简单向文件追加文本的方法AppendAllText

C#里最简单向文件追加文本的方法AppendAllText 在开发的过程中,经常会碰到这样的问题,就是当一个文件没有创建时,就需要创建。但是文件已经创建了,就直接追加数据。 比如我们开发一个记录每天温度的软件, 每天都在固定的时间去记录一下这个温度,那么就需要在这个文件后面…

【第一章】SQL基础知识

目录 ​编辑 1. 认识SQL 1.1 SQL的标准 1.2 SQL的种类 1.3 SQL的功能 2. 常量 2.1 数字常量 2.2 字符串常量 2.3 日期和时间常量 2.4 符号常量 3. 变量 3.1 局部变量 3.2 全局变量 4. 运算符 4.1 算术运算符 4.2 比较运算符 4.3 逻辑运算符 4.4 按位运算符 …

Redis沙盒逃逸漏洞(CVE-2022-0543)复现以及流量特征分析

Redis简介 Redis Labs Redis是美国Redis Labs公司的一套开源的使用ANSI C编写、支持网络、可基于内存亦可持久化的日志型、键值&#xff08;Key-Value&#xff09;存储数据库&#xff0c;并提供多种语言的API。 漏洞介绍 Redis 存在代码注入漏洞&#xff0c;攻击者可利用该漏…

Android MVVM之CreationExtras创建ViewModel的详解与使用

一、介绍 CreationExtras是Android api在Androidx-Lifecycle 在近期迈入到了 2.5.0 版本中。很多人第一眼看到&#xff0c;不知道这是个什么&#xff0c;看到会觉得云里雾里&#xff0c;无从下手&#xff0c;也不知道到底该怎么做。这个和现有的ViewModel搭配使用。他不能单独使…

公链年度数据报告:2022年发生了什么,行业将走向何方?

Date&#xff1a;2023 年 1 月Data Source: Footprint Analytics - Chain overview这份年度链报告审视了过去一年 Footprint Analytics 上的数据&#xff0c;以分析各公链的关键趋势。在 2022 年&#xff0c;大多数加密货币头条新闻并不涉及链本身。虽然&#xff0c;像三箭、Bl…

SQLSERVER 的四个事务隔离级别到底怎么理解?

一&#xff1a;背景 1. 讲故事 在有关SQLSERVER的各种参考资料中&#xff0c;经常会看到如下四种事务隔离级别。 READ UNCOMMITTEDREAD COMMITTEDSERIALIZABLEREPEATABLE READ 随之而来的是大量的文字解释&#xff0c;还会附带各种 脏读, 幻读, 不可重复读 常常会把初学者弄…

【微信小程序学习第3天——网络数据请求

一、小程序网络请求限制 1、必须https类型的接口 2、必须将接口的域名添加到信任列表中 二、配置request合法域名 配置步骤&#xff1a;登录微信小程序管理后台 -> 开发 -> 开发设置 -> 服务器域名 -> 修改 request 合法域名 点击修改request合法域名&#xf…

全流程搞清楚 Kubernetes API 的使用,可进行业务二次开发对接 k8s 调用,详细图文说明以及常见问题整理

全流程搞清楚 Kubernetes API 的使用&#xff0c;可进行业务二次开发对接 k8s 调用&#xff0c;详细图文说明以及常见问题整理。 使用CLI&#xff08;如curl&#xff09;或GUI&#xff08;如postman&#xff09;HTTP客户端调用Kubernetes API有很多理由。例如&#xff0c;你可…