Автор оригинала: Abhishek Bansal.
Реактивный способ программирования делает многие сложные задачи бесконечно простыми. Этот пост проливает некоторый свет на реактивные и императивные способы решения проблемы. Я попытаюсь объяснить, как реактивное программирование облегчает жизнь разработчику, делая больше за меньшее количество кода.
Постановка проблемы
Рассмотрим следующую постановку задачи:
- Вы должны выполнить вызов API, который возвращает сопоставление идентификатора объекта объекту.
- Вам нужно преобразовать эту карту в список объектов, содержащих идентификатор объекта.
- Теперь вам нужно отфильтровать некоторые объекты из этого списка.
- Для каждого из этих отфильтрованных объектов вам необходимо выполнить еще один вызов API.
- Вышеуказанные вызовы API должны выполняться последовательно. Каждый последующий вызов API должен выполняться с задержкой в 100 миллисекунд.
Это реальный жизненный сценарий. Я написал реализацию для этого в одном из наших приложений для Android. Мы используем Дооснащение для создания сетей, RxJava-2 для реактивного программирования и |/Retrolambda для Java 8, как синтаксис и сокращение шаблонов.
Теперь подумайте о том, как вы будете реализовывать это в императивном мире.
Императивный Путь
Позволь мне помочь тебе. В императивном мире:
- Вероятно, вы выполните вызов API с помощью дооснащения (если вы используете дооснащение) или в асинхронной задаче.
- Когда этот API вернется, вы повторите карту и преобразуете ее в список в основном потоке (конечно, вы можете сделать это в другом потоке, но я хочу, чтобы все было просто).
- Затем вы должны выполнить вторую итерацию для фильтрации нужных объектов.
- Теперь все становится интересным, потому что вам нужно выполнить вызовы API для каждого из этих оставшихся объектов в списке. Вероятно, вам потребуется написать службу или AsyncTask, которая теперь выполняет синхронные вызовы API после времени ожидания 100 мс.
Это большая работа, и я даже не рассматриваю крайние случаи и обработку ошибок для простоты. Подумайте о случае, когда API возвращает большой список объектов, и вы не можете позволить себе обрабатывать его в основном потоке.
Что ж, Rx делает всю эту тяжелую работу за вас. Давайте посмотрим, как это сделать.
Способ Rx
Реактивное программирование-это совершенно другой подход к написанию кода. Все в реактивном мире считается потоком. Эти потоки неизменяемы, и существует множество доступных операторов, которые работают с этими потоками. Реальная сила реактивного программирования заключается в этих проверенных операторах.
Rx делает задачу переключения между потоками такой же простой, как яблочный пирог. Наша вышеприведенная постановка задачи может быть выполнена с помощью RxJava всего лишь 10 строками кода.
Вот пример из производственного кода:
APIProvider.getInstance() .getService() .getMyObjects(userName) .subscribeOn(Schedules.io()) .map(MyObject::toList) .flatMap(rx.Observable::from) .filter(myObject->myObject.getName().equals(Constants.SOME_NAME)) // adding a 10ms delay in subsequent api calls .flatMap(myObject -> Observable.timer(100, TimeUnit.MILLISECONDS).map(y -> myObject)) .doOnNext(rule -> { // deleting my object one by one APIProvider.getInstance() .getService() .deleteMyObject(userName, rule.getId()) .subscribe(); }) .subscribe();
Давайте разберемся в этом коде строка за строкой:
APIProvider.getInstance().getService().getMyObjects(userName)
Это Модифицируйте
способ выполнения вызова API. Этот API возвращает карту MyObjectId
к Моему объекту
. Пример JSON выглядит так:
{"1":{"name":"object1"},"2":{"name":"object2"}}
.subscribeOn(Schedules.io())
subscribeOn
– это оператор Rx, который направляет RxJava для запуска обработки в потоке планировщика (фоновом потоке). Только эта строка позволяет переключить обработку в фоновый поток. Как это здорово!
Map
– это оператор преобразования, который позволяет нам преобразовывать объекты. Здесь мы преобразуем Карта
в Список
. тоЛист
– это статический метод, написанный в классе MyObject
. Этот метод преобразует Map<Идентификатор объекта, MyObject>
в Список
. Версия списка содержит идентификаторы объектов в самом объекте. Мой объект::перечислить
– это способ вызова этого метода на Java 8 с именем Ссылка на метод . Преобразованная структура данных теперь выглядит следующим образом:
[{"id":"1","name":"object1"},{"id":"2","name":"object2"}]
.flatMap(rx.Observable::from)
Это утверждение позволяет нам получать каждый MyObject
как отдельные события в наблюдаемом потоке. До этого у нас был целый список или Карта как одно событие в наблюдаемом потоке. Чтобы выполнить фильтрацию и вызовы API для каждого из них отдельно, нам нужно, чтобы они были независимыми событиями в потоке.
.filter(myObject->myObject.getName().equals(Constants.SOME_NAME))
Это довольно очевидно. Оператор Filter
позволяет нам отфильтровывать события, которые не соответствуют критериям фильтрации. Любой объект, имя которого не совпадает с константами . SOME_NAME
не разрешается распространяться дальше в потоке.
.flatMap(myObject -> Observable.timer(100, TimeUnit.MILLISECONDS).map(y -> myObject))
Этот интересный фрагмент кода позволяет нам добавить задержку в 100 мс между последующими результатами. Внутри flatmap
мы создаем другой поток , используя Таймер
наблюдаемый. Согласно документации, Таймер
возвращает наблюдаемое, которое выдает одно число ноль после указанного вами периода задержки.
Поскольку мы не хотим потерять наши MyObjects
, нам нужно сопоставить этот ноль обратно с Моим объектом
. Внешняя плоская карта
следит за тем, чтобы события принимались в текущем потоке.
doOnNext(myObject -> { // deleting my object one by one APIProvider.getInstance().getService() .deleteMyObject(userName, myObject.getId()) .subscribe(); })
Наконец, поскольку у нас есть хороший поток Мои объекты
, включая задержку в 100 мс, мы можем выполнять наши вызовы API. Это то, что происходит внутри оператора doOnNext
. Оператор doOnNext
позволяет нам добавлять зацепку для каждого события в потоке.
Огонь! Вот что делает этот оператор. Это самая простая версия оператора Subscribe
, которую мы использовали здесь. Вы можете прочитать больше об этом в документах.
Если вы заметили, вся эта работа происходит в фоновом режиме, и нам не нужно ни о чем беспокоиться. В моем случае мне не нужно было обрабатывать результаты API в главном потоке Android. Но, в случае необходимости, вы можете просто использовать оператор observeOn
для переключения потоков в любое время.
Итак, что вы об этом думаете? Дайте мне знать в комментариях.
Счастливого кодирования!!
Оригинал: “https://www.codementor.io/@abhishekbansal813/the-rx-way-of-doing-things-fgox8sp1n”