Я недавно столкнулся с вопросом об использовании 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
.
Если вы видите какие-либо улучшения, которые могут быть сделаны, или у вас другой подход к проблеме, поделитесь своими мыслями.