Если вы разработчик для Android, то, возможно, вы слышали много хорошего о RxJava, популярной реализации библиотеки ReactiveX с открытым исходным кодом, которая переносит реактивное программирование на виртуальную машину Java (JVM).
RxJava разработан для того, чтобы избавиться от боли при работе с асинхронными потоками данных, хотя, как вы увидите, определение «данных» в RxJava довольно широкое. Поскольку RxJava является JVM-совместимой библиотекой, вы можете использовать ее на самых разных платформах, но в этой серии я покажу вам, как использовать RxJava 2 для разработки под Android.
К концу этой серии вы освоите все основы RxJava 2, так что вы сможете приступить к созданию высокореактивных приложений, которые могут обрабатывать широкий спектр синхронных и асинхронных данных — и все это с использованием кода, который будет более кратким и управляемым, чем обычно в состоянии достичь только с помощью Java.
В дополнение к введению для новичков в RxJava, если вы ветеран RxJava 1, который хочет совершить прыжок в RxJava 2, то эта серия поможет сделать этот переход максимально плавным. Хотя обновление до последней версии библиотеки может показаться не таким уж большим делом, RxJava 2 не является вашим типичным обновлением — это полное переписывание RxJava. С таким большим количеством изменений легко запутаться, поэтому, потратив некоторое время на ознакомление с RxJava 2 с точки зрения новичка, вы сможете сэкономить много времени и разочароваться в долгосрочной перспективе.
В этом первом посте я расскажу о том, что такое RxJava и какие основные преимущества он предлагает разработчикам Android. Мы также подробно рассмотрим основные компоненты любого проекта RxJava: Observers
, Observables
и подписки. К концу этого урока вы создадите простое приложение в стиле «Hello World», которое включает в себя все эти основные компоненты.
Другими основными строительными блоками RxJava являются операторы, поэтому во второй части я расскажу о различных способах использования операторов для преобразования, объединения, фильтрации и манипулирования данными вашего приложения.
В последней части мы выйдем за пределы базовой библиотеки RxJava и рассмотрим RxAndroid — целую библиотеку, которая содержит все специфичные для Android расширения, которые вам понадобятся, чтобы раскрыть весь потенциал реактивного программирования для Android.
Нам есть что рассказать, поэтому давайте начнем с основ:
Что такое RxJava?
RxJava — это библиотека, которая позволяет создавать приложения в стиле реактивного программирования. По своей сути реактивное программирование обеспечивает чистый и эффективный способ обработки и реагирования на потоки данных в реальном времени, включая данные с динамическими значениями.
Эти потоки данных не обязательно должны принимать форму традиционных типов данных, поскольку RxJava в значительной степени рассматривает все как поток данных — все, начиная от переменных и заканчивая свойствами, кэшами и даже событиями пользовательского ввода, такими как щелчки и пролистывания.
Данные, передаваемые каждым потоком, могут быть либо значением, ошибкой, либо «завершенным» сигналом, хотя вам необязательно реализовывать последние два. Создав потоки, передающие данные, вы объединяете их с реактивными объектами, которые потребляют, а затем воздействуют на эти данные, выполняя различные действия в зависимости от того, что испустил поток. RxJava включает в себя целый ряд полезных операторов для работы с потоками , что позволяет легко выполнять такие операции, как фильтрация, отображение, задержка, подсчет и многое другое.
Чтобы создать этот рабочий поток потоков данных и объектов, которые на них реагируют, RxJava расширяет шаблон проектирования программного обеспечения Observer. По сути, в RxJava у вас есть объекты Observable
которые генерируют поток данных, а затем завершаются, и объекты Observer
которые подписываются на Observable
s. Observer
получает уведомление каждый раз, когда назначенный ему объект Observable
испускает значение, ошибку или завершенный сигнал.
Итак, на очень высоком уровне RxJava — это все о:
- Создание
Observable
. - Предоставляя
Observable
некоторые данные для излучения. - Создание
Observer
. - Присвоение
Observer
Observable
. - Предоставление задачам
Observer
для выполнения всякий раз, когда он получает излучение от назначенногоObservable
.
Почему RxJava?
Изучение любой новой технологии требует времени и усилий, и как библиотека, ориентированная на данные, RxJava не всегда является самым простым API, с которым можно справиться.
Чтобы помочь вам решить, стоит ли изучение RxJava начальных инвестиций, давайте рассмотрим некоторые ключевые преимущества добавления библиотеки RxJava в ваши проекты Android.
Более краткий, читаемый код
Сложный, многословный и сложный для чтения код — это всегда плохие новости. Грязный код более подвержен ошибкам и другим недостаткам, и если какие-либо ошибки все же произойдут, вам придется гораздо сложнее отследить источник этих ошибок, если ваш код содержит ошибки.
Даже если ваш проект собирается без каких-либо ошибок, сложный код все еще может преследовать вас — обычно, когда вы решаете выпустить обновление для вашего приложения через несколько месяцев, загрузите свой проект и сразу столкнетесь со стеной запутанного, запутанного кода!
RxJava упрощает код, необходимый для обработки данных и событий, позволяя вам описывать, чего вы хотите достичь, вместо того, чтобы писать список инструкций для вашего приложения для проработки. RxJava также предоставляет стандартный рабочий процесс, который вы можете использовать для обработки всех данных и событий в вашем приложении — создать Observable
, создать Observer
, назначить наблюдаемое этому наблюдателю, промыть и повторить. Этот формульный подход делает очень простой, понятный человеку код.
Многопоточность Made Easy
Современные приложения Android должны быть в состоянии многозадачности. По крайней мере, ваши пользователи будут ожидать продолжения взаимодействия с пользовательским интерфейсом вашего приложения, пока ваше приложение выполняет некоторую работу в фоновом режиме, например, управление сетевым подключением, загрузка файла или воспроизведение музыки. Проблема в том, что Android по умолчанию является однопоточным, поэтому, если ваше приложение когда-либо успешно справляется с несколькими задачами, вам нужно создать дополнительные потоки.
Из коробки Android предоставляет несколько способов создания дополнительных потоков, таких как сервисы и IntentServices
, но ни одно из этих решений не особенно легко реализовать, и они могут быстро привести к сложному, подробному коду, подверженному ошибкам.
RxJava стремится избавить от необходимости создавать многопоточные приложения для Android, предоставляя специальные планировщики и операторов. Это дает вам простой способ указать ветку, где должна быть выполнена работа, и ветку, где должны быть опубликованы результаты этой работы. RxJava 2.0 включает в себя несколько планировщиков по умолчанию, в том числе Schedulers.newThread
, что особенно полезно при создании нового потока.
Чтобы изменить поток, в котором выполняется работа, вам просто нужно изменить место, где наблюдатель подписывается на наблюдаемое, используя оператор subscribeOn
. Например, здесь мы создаем новый поток и указываем, что работа должна выполняться в этом новом потоке:
1
|
observable.subscribeOn(Schedulers.newThread())
|
Другая давняя проблема с многопоточностью на Android заключается в том, что вы можете обновлять пользовательский интерфейс своего приложения только из основного потока. Как правило, когда вам нужно опубликовать результаты некоторой фоновой работы в пользовательском интерфейсе вашего приложения, вы должны создать выделенный Handler
.
Еще раз, RxJava имеет гораздо более простое решение. Вы можете использовать оператор observeOn
чтобы указать, что Observable должен отправлять свои уведомления, используя другой планировщик, который, по сути, позволяет отправлять данные Observable потоку по вашему выбору, включая основной поток пользовательского интерфейса.
Это означает, что с помощью всего двух строк кода вы можете создать новый поток и отправить результаты работы, выполненной в этом потоке, в основной поток пользовательского интерфейса Android:
1
2
|
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
|
Итак, технически мы немного обманываем, поскольку AndroidSchedulers.mainThread
доступен только как часть библиотеки RxAndroid, которую мы не будем рассматривать до третьей части. Тем не менее, этот пример дает вам представление о возможностях RxJava и RxAndroid для упрощения области разработки Android, которая известна своей чрезмерной сложностью.
Повышенная гибкость
Наблюдаемые объекты излучают свои данные таким образом, чтобы полностью скрыть способ их создания. Поскольку ваши наблюдатели не могут даже увидеть, как были созданы данные, вы можете свободно реализовать свои Observable
как вам захочется.
После того, как вы реализовали свои Observable
, RxJava предоставляет огромный спектр операторов, которые вы можете использовать для фильтрации, объединения и преобразования данных, излучаемых этими Observable
. Вы даже можете объединять все больше и больше операторов, пока не создадите именно тот поток данных, который необходим вашему приложению.
Например, вы можете объединить данные из нескольких потоков, отфильтровать вновь объединенный поток, а затем использовать полученные данные в качестве входных данных для последующего потока данных. И помните, что в RxJava практически все рассматривается как поток данных, поэтому вы даже можете применять эти операторы к нетрадиционным «данным», таким как события щелчка.
Создайте больше адаптивных приложений
Прошли те времена, когда приложению удавалось загружать страницу контента, а затем ждать, пока пользователь нажмет кнопку « Далее» . Сегодня ваше типичное мобильное приложение должно реагировать на постоянно растущее разнообразие событий и данных, в идеале в режиме реального времени. Например, ваше типичное приложение для социальных сетей должно постоянно прослушивать входящие лайки, комментарии и запросы друзей, одновременно управляя сетевым подключением в фоновом режиме и реагируя немедленно, когда пользователь нажимает или проводит пальцем по экрану.
Библиотека RxJava была разработана для того, чтобы иметь возможность управлять широким диапазоном данных и событий одновременно и в режиме реального времени, что делает ее мощным инструментом для создания приложений с высокой чувствительностью, которые ожидают современные мобильные пользователи.
Добавление RxJava в Android Studio
Если вы решили, что в RxJava есть что предложить вашей практике разработки под Android, то первым шагом к тому, чтобы стать мастером RxJava, является добавление библиотеки в ваш проект.
Создайте новый проект Android Studio с настройками по вашему выбору, а затем откройте файл build.gradle уровня модуля и добавьте в качестве зависимости последнюю версию io.reactivex.rxjava2:rxjava
.
На момент написания RxJava 2.0.5 был самым последним выпуском, поэтому мой файл build.gradle выглядит так:
01
02
03
04
05
06
07
08
09
10
11
12
|
dependencies {
compile fileTree(dir: ‘libs’, include: [‘*.jar’])
androidTestCompile(‘com.android.support.test.espresso:espresso-core:2.2.2’, {
exclude group: ‘com.android.support’, module: ‘support-annotations’
})
compile ‘com.android.support:appcompat-v7:25.1.0’
testCompile ‘junit:junit:4.12’
compile ‘io.reactivex.rxjava2:rxjava:2.0.5’
}
|
При появлении запроса нажмите « Синхронизировать сейчас» .
Затем откройте файл MainActivity
и добавьте импорт, необходимый для начала работы с основными функциями RxJava:
1
2
3
4
5
|
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
|
Если вы мигрируете из RxJava 1, то этот импорт может оказаться не таким, как вы ожидали, так как RxJava 1 использовал совершенно другое имя пакета (если быть точным, rx
).
Однако это не произвольное изменение имени: разные имена пакетов дают вам возможность использовать RxJava 1 и RxJava 2 бок о бок в одном проекте. Если вы находитесь на полпути к проекту, который использует RxJava 1, то вы можете добавить библиотеку RxJava 2 и сразу же начать использовать обновленные функции 2, не нарушая ни один из ваших кодов RxJava 1.
Если вы начинаете свое путешествие по RxJava с версией 2, просто имейте в виду, что если вы столкнулись с какими-либо учебниками или кодом по RxJava, использующими имя пакета rx
, то это код RxJava 1, и он вряд ли будет совместим с библиотекой версии 2.
Строительные блоки RxJava
До сих пор мы смотрели на RxJava только на очень высоком уровне. Пришло время конкретизировать и детально рассмотреть два наиболее важных компонента, которые будут появляться снова и снова на протяжении всей вашей работы с RxJava: Observer
s и Observable
s.
К концу этого раздела вы не только получите четкое представление об этих двух основных компонентах, но и создадите полностью функционирующее приложение, состоящее из Observable
которое генерирует данные, и Observer
который реагирует на эти выбросы.
Создать Observable
Observable
похож на Iterable
в том, что, учитывая последовательность, он будет проходить через эту последовательность и испускать каждый элемент, хотя Observable
обычно не начинает выдавать данные, пока Observer
подпишется на них.
Каждый раз, когда Observable
испускает элемент, он уведомляет назначенного Observer
с помощью onNext()
. Как только Observable
передал все свои значения, он завершается вызовом:
-
onComplete
: вызывается, если операция прошла успешно. -
onError
: Вызывается, если былоonError
Exception
.
Давайте посмотрим на пример. Здесь мы создаем Observable, который испускает числа 1 , 2 , 3 и 4 , а затем завершается.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
//Use onNext to emit each item in the stream//
e.onNext(1);
e.onNext(2);
e.onNext(3);
e.onNext(4);
//Once the Observable has emitted all items in the sequence, call onComplete//
e.onComplete();
}
}
);
|
Обратите внимание, что в этом примере я подробно объясняю, что происходит, поэтому не позволяйте большому количеству кода вас оттолкнуть! Это гораздо больше кода, чем вы обычно используете для создания Observable
в ваших реальных проектах RxJava.
Создать наблюдателя
Observer
— это объекты, которые вы назначаете для Observable
с помощью оператора subscribe()
. Как только Observer
подписан на Observable
, он будет реагировать всякий раз, когда его Observer
испускает одно из следующих:
-
onNext
:Observable
выпустил значение. -
onError
: Произошла ошибка. -
onComplete
:Observable
завершил излучение всех своих значений.
Давайте создадим Observer
который подписан на наши 1, 2, 3, 4 Observable
. Чтобы упростить onNext
, этот Observer
будет реагировать на onNext
, onError
и onComplete
, печатая сообщение на Logcat Monitor в Android Studio:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
Observer<Integer> observer = new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
Log.e(TAG, «onSubscribe: «);
}
@Override
public void onNext(Integer value) {
Log.e(TAG, «onNext: » + value);
}
@Override
public void onError(Throwable e) {
Log.e(TAG, «onError: «);
}
@Override
public void onComplete() {
Log.e(TAG, «onComplete: All Done!»);
}
};
//Create our subscription//
observable.subscribe(observer);
|
Откройте монитор Logcat в Android Studio, выбрав вкладку « Монитор Android » в нижней части окна Android Studio (где курсор расположен на скриншоте ниже), а затем выберите вкладку « Logcat ».
Чтобы протестировать этот код, подключите физическое устройство Android к компьютеру для разработки или запустите проект на совместимом AVD. Как только ваше приложение появится на экране, вы должны увидеть данные, передаваемые вашим Observable.
Создание наблюдаемого с меньшим количеством кода
Хотя наш проект успешно передает данные, код, который мы используем, не совсем лаконичен, особенно код, который мы используем для создания нашего Observable
.
К счастью, RxJava предоставляет ряд удобных методов, которые позволяют вам создавать Observable
используя гораздо меньше кода:
1. Observable.just ()
Вы можете использовать оператор .just()
для преобразования любого объекта в Observable
. Результат Observable
затем испустит исходный объект и завершит.
Например, здесь мы создаем Observable
который будет выдавать одну строку всем своим Observers
:
1
|
Observable<String> observable = Observable.just(«Hello World!»);
|
2. Observable.from()
Оператор .from()
позволяет вам конвертировать коллекцию объектов в наблюдаемый поток. Вы можете преобразовать массив в Observable
используя Observable.fromArray
, Callable
в Observable
используя Observable.fromCallable
, и Iterable
в Observable
используя Observable.fromIterable
.
3. Observable.range()
Вы можете использовать оператор .range()
для .range()
диапазона последовательных целых чисел. Первое целое число, которое вы предоставляете, является начальным значением, а второе — это число целых чисел, которое вы хотите выдать. Например:
1
|
Observable<Integer> observable = Observable.range(0, 5);
|
4. Observable.interval()
Этот оператор создает Observable
который испускает бесконечную последовательность возрастающих целых чисел, причем каждое излучение отделяется выбранным вами интервалом времени. Например:
1
|
Observable<Long> observable = Observable.interval(1, TimeUnit.SECONDS)
|
5. Observable.empty()
Оператор empty()
создает Observable
который не генерирует никаких элементов, но обычно завершается, что может быть полезно, когда вам нужно быстро создать Observable
для целей тестирования.
1
|
Observable<String> observable = Observable.empty();
|
Вывод
В этой статье мы рассмотрели основные строительные блоки RxJava.
На этом этапе вы знаете, как создавать и работать с Observers
и Observables
и как создать подписку, чтобы ваши Observables
могли начать излучать данные. Мы также кратко рассмотрели несколько операторов, которые позволяют вам создавать диапазон различных Observables
, используя гораздо меньше кода.
Однако операторы — не просто удобный способ сократить объем кода, который вам нужно написать! Создать Observer
и Observable
достаточно просто, но операторы — это место, где вы действительно начинаете понимать, что возможно с RxJava.
Итак, в следующем посте мы рассмотрим некоторые из самых мощных операторов RxJava, включая операторов, которые, наконец, могут сделать многопоточность на Android безболезненной. Оставайтесь с нами, чтобы узнать реальную мощь библиотеки RxJava.
А пока посмотрите другие наши посты и курсы о разработке Android здесь на Envato Tuts +!
-
Android StudioСоздание функциональных приложений для Android в Kotlin: начало работы
-
AndroidКодирование Android-приложения с флаттером и дротиком
-
Android SDKЧто нового в Firebase? Обновления с саммита разработчиков Firebase
-
AndroidПеренос приложения Android на дизайн материалов
Наблюдаемые диаграммы потоков данных взяты из документации ReactiveX и лицензированы по лицензии Creative Commons Attribution 3.0.