我有一个关于什么是更好的RxJava模式以保持可观察状态的问题。
为了简单起见,我们假设我们有一个StateManager
类需要跟踪某个状态(让我们假设它是一个简单的布尔标志)系统并以可观察的方式公开它。因此,它将采用如下方法:
class StateManager {
Observable<Boolean> state();
...
}
这位经理的生命周期很长,可能有多个客户&#34; (例如,观点,其他经理等),可以随时订阅或取消订阅。国家将根据一些内部事件进行更改。
最明显的处理方法是将状态保存在消费者直接挂钩的BehaviourSubject
中:
class StateManager {
Subject mStateSubject = BehaviourSubject.create(true);
Observable<Boolean> state() {
return mStateSubject.asObservable();
}
...
}
有更好的方法吗?
答案 0 :(得分:2)
Subjects
可能是使用反应库的最不理想的方法,尽管它肯定可行。
功能反应式编程在没有状态的情况下效果最佳。 Subjects
是一种国家形式。我建议更改代码,以便将Observable定义为功能操作符的组合。这样可以轻松测试和管理您的observable发出的消息。
我更像是一名C#开发人员,所以我希望你能原谅不同的语法。这是一个例子:
void Main()
{
var tracker = new AddTracker();
tracker.getSums().Subscribe(i => Console.WriteLine(i));
Observable.Interval(TimeSpan.FromMilliseconds(100))
.Timestamp()
.Select(t => t.Timestamp.Second)
.Take(20)
.Subscribe(i => tracker.setA(i % 7));
Observable.Interval(TimeSpan.FromMilliseconds(75))
.Timestamp()
.Select(t => t.Timestamp.Millisecond)
.Take(30)
.Subscribe(i => tracker.setB(i % 9));
}
public class AddTracker
{
private readonly ISubject<int> _a;
private readonly ISubject<int> _b;
private readonly IObservable<int> _sums;
private readonly IDisposable _dummySub;
public AddTracker()
{
_a = new BehaviorSubject<int>(0);
_b = new BehaviorSubject<int>(0);
_sums = _a
.CombineLatest(_b, (a, b) => a + b)
.Replay(1)
.RefCount();
_dummySub = _sums.Subscribe(_ => { });
}
public void setA(int value)
{
_a.OnNext(value);
}
public void setB(int value)
{
_b.OnNext(value);
}
public IObservable<int> getSums()
{
return _sums;
}
}
在C#land中,您可以将_a
和_b
主题换成事件,这是一个温和的改进。我知道Java中没有一流的事件,所以我不确定会翻译。
然而,更基本的是,在C#和Java中,您应该问的问题是......导致setA
和setB
调用的原因是什么?你能用这个代替它们吗?
void Main()
{
var aStream = Observable.Interval(TimeSpan.FromMilliseconds(100))
.Timestamp()
.Select(t => t.Timestamp.Second)
.Take(20);
var bStream = Observable.Interval(TimeSpan.FromMilliseconds(75))
.Timestamp()
.Select(t => t.Timestamp.Millisecond)
.Take(30);
var tracker = new AddTracker(aStream, bStream);
tracker.getSums().Subscribe(i => Console.WriteLine(i));
}
public class AddTracker
{
private readonly IObservable<int> _sums;
private readonly IDisposable _dummySub;
public AddTracker(IObservable<int> a, IObservable<int> b)
{
_sums = a
.CombineLatest(b, (aItem, bItem) => (aItem % 9) + (bItem % 7))
.Replay(1)
.RefCount();
_dummySub = _sums.Subscribe(_ => {});
}
public IObservable<int> getSums()
{
return _sums;
}
}
简而言之,如果必须,请从主题开始。然后带走你的主题,并尽可能远离你的逻辑推动它们。
答案 1 :(得分:1)
所描述的案例就是所谓的'热'可观察 - 可观察到其生产者(排放源)在订阅之外创建, (正如Ben Lesh在Hot vs Cold Observables所述 - 建议阅读)。
正如Shlomo所说,受试者是Rx世界的“可变变量”,你可以通过使用Obsevable.create(听取事件并根据事件产生排放)来创造一个“冷”观察者,然后使用将其转换为ConnectableObservable(如share,publish)的运算符使其“热”,以便将其多播到多个不同时间订阅的观察者。但是,在这种情况下,由于生产者是你的班级的本地人(事件是由这个班级生成的),所以可以使用主题来达到这个目的,因为你的班级本身就是排放源和产生事件的相互/状态变量。 (基于answer given by Erik Meijer和此blog post)