我最近遇到了关于Subject
用法的讨论,就像这里的https://github.com/JakeWharton/RxRelay/issues/7
我看到很多人都说应该避免使用Subject
,有些人甚至说Subject
的任何使用本质上是一种不好的做法。尽管我在Subject
可以而且应该避免的理论水平上达成共识,但我几乎无法摆脱实际实践中的主题。这样做似乎不切实际,甚至是不可能的。
想象一个简单的理论天气应用,它只有两件事:
显示当前天气信息的视图
刷新按钮,可从服务器重新获取天气信息。
(为简单起见,我们假设该应用在首次启动时不会显示数据,但会等待用户至少按下一次刷新按钮。)
然后您可以想到这样的视图模型设计:
ViewModel
interface IWeatherViewModel {
// Provides weather data
Flowable<WeatherData> getWeatherDataToDisplay();
// Lets view to refresh
void refresh();
}
如果我使用Subject
,则IWeatherViewModel
可以这样实现:
class WeatherViewModel implements IWeatherViewModel {
private final BehaviorProcessor<WeatherData> weatherData = BehaviorProcessor.create();
private final PublishProcessor<Boolean> eventRefresh = PublishProcessor.create();
WeatherViewModel() {
eventRefresh
.flatMapSingle(x -> getWeatherData())
.subscribe(weatherData);
}
// Provides weather data
public Flowable<WeatherData> getWeatherDataToDisplay() {
weatherData.hide();
}
// Lets view to refresh
public void refresh() {
eventRefresh.onNext(true);
}
private Single<WeatherData> getWeatherData() {
... // omitted for simplicity
}
}
这个想法是让一个PublishProcessor
会在每次调用refresh()
时发出刷新事件,然后将其传播到BehaviorSubject
。 getWeatherDataToDisplay()
成功后,将通知所有观察getWeatherData()
的订户。
但是,如果没有Subject
,我很难实现同一件事。
refresh()
调用才能流式传输。我也许可以用PublishProcessor
来代替Flowable.create()
,但看起来一点也不干净,我能做的最好的事情是:
private FlowableEmitter emitter;
private final Flowable<Boolean> eventRefresh = Flowable.create(emitter -> {
this.emitter = emitter;
}, BackpressureStrategy.BUFFER);
public void refresh() {
emitter.onNext(true);
}
现在我突然不得不拥有一个我不能定型的新实例变量。
BehaviorProcessor
的运算符,也找不到任何可在订阅后立即发出最新项目的热门可观察物。此行为是必需的,因为视图应该能够像LiveData
一样无缝地分离和重新附加。如果您看到可以改进的地方,或者对问题有不同的解决方法,请分享您的想法。