понедельник, 22 июня 2015 г.

Залізна людина тепер реактивна: RxJava

Дана стаття присвячена перевагам, що можуть бути надані нашим проектам деякими функціональними штрихами.
Фреймворки типу RxJava та ReactiveX можуть легко вправитися з середовищами, що працюють у фоні та в UI потоці.
Ця стаття також фокусується на тому, як оператори можуть мінімізувати час на загальну розробку завдань, реактивні розширення пропонують широкий спектр операторів, щоб зробити ваше життя простіше.
Як завжди, код на Github, не соромтеся коментувати, відкрити питання або скаржитися!.

RetroLambda

Інколи, у великих додатках, розроблених з Java, або великих фреймворках як android дуже важко, чи навіть неможливо (android) використовувати можливості Java 8 такі як лямда-вирази
Retrolambda це бекпорт, що з'явився для вирішення даної проблеми, переклад байткодів Java 8 на попередні версії Java дає можливість користуватися лямда-виразами та іншими можливостями нової платформи.

Retrolamda може працювати з Gradle та Maven, я обрав Gradle так як він йде в комплекті з Android Studio, для використання вам досить додати в корінь файлу build.gradle плагін Retrolambda та застосувати у вашому модулі build.gradle, встановити рівень мови на 1.8 в Android Studio і все готово.

build.gradle (root)
    dependencies {
        classpath 'me.tatarka:gradle-retrolambda:3.1.0'
{ваш модуль}/build.gradle
    apply plugin: 'me.tatarka.retrolambda'

    android { 

        ...

        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
    }
}

Retrolambda дозволяє вам писати менше шаблонного коду, а також робить код зрозумілішим. У цьому прикладі написаному Den Lew ви можете побачити різницю.

Без використання RetroLambda
Observable.just("Hello, world!")
    .subscribe(new Action1<String>() {
        @Override
        public void call(String s) {
              System.out.println(s);
        }
    });
З використанням RetroLambda
Observable.just("Hello, world!") .subscribe(
    s -> System.out.println(s)
);

А тепер на прикладі додатку Месники:

mCharacterSubscription = mGetCharacterInformationUsecase
    .execute().subscribe(
        character -> onAvengerReceived(character),
        error     -> manageError(error)
    );

mComicsSubscription = mGetCharacterComicsUsecase
    .execute().subscribe(
        comics -> Observable.from(comics).subscribe(
            comic -> onComicReceived(comic)),
        error  -> manageError(throwable)
    );

ReactiveX

ReactiveX - це колекція з проектів з відкритим вихідним кодом серед їх основних принципів є шаблон проектування Спостерігач, шаблон Ітератор та функціональне програмування.
ReactiveX також має API для асинхронного програмування, з цим фреймворком насправді дуже легко реалізовувати завдання асинхронно.

ReactiveX як асинхронний клієнт

Гарна штука, що користуєчись ReativeX можна створювати повністю асинхронний API чи клієнт, а потім вже при реалізації вирішувати, який код буде працювати асинхронно чи в окремому потоці (Thread) чи синхронно.  
Таким чином, ми маємо спостережуваний API, а не блокуючий API.

public interface Usecase<T> {

    Observable<T> execute();
}
public interface Repository {

    Observable<Character> getCharacter (final int characterId);

    Observable<List<Comic>> getCharacterComics (final int characterId);
} 
 

Чим же насправді є RxJava

Клас Observable створює об'єкт чи серію об'єктів ці об'єкти отримуються методом Observer, що наледить класу "Observable".


Необхідно щоб Observer був прив'язаний до Observable, в іншому випадку Observer не видасть нічого. Коли Observer пррив'язаний, об'єкт типу Subscription створюється, він  використовується для відв'язування Observable, це крисно при роботі з Activity та Fragment в методах onStop чи onPause, наприклад.

mCharacterSubscription = mGetCharacterInformationUsecase
    .execute().subscribe( ... );
@Override
public void onStop() {

    if (!mCharacterSubscription.isUnsubscribed())
        mCharacterSubscription.unsubscribe();

    if (!mComicsSubscription.isUnsubscribed())
        mComicsSubscription.unsubscribe();
} 
 
Коли Observer прив'язаний до Observable він має отримати три методи.
  • onNext (T) метод для отримання об'єктів позначиених 'Observable' помилковими
  • onError (Exception), метод який викликається при виявленні помилок
  • onCompleted(), метод який викликаєть коли Observable завершує створення об'єктів.

Обожнюю цю картинку:)

Компоненти зв'язку

Тепер подивимось на те як можна використовувати GetCharacterInformationUsecase. Варіаннти реалізації інтерфейсу Usecase <T>:

public interface Usecase<T> {

    Observable<T> execute();
}
 
Коли usecase запущено - повертається об'єкт типу Observable, корисна можливість бути зв'язаним з observable та операторами з меншими зусиллями, ми ще побачимо велику силу операторів в подальшому.
Коли ми запускаємо GetCharacterInformationUsecase ми говоримо нашому репозиторію запросити у відведеного джерела даних:

@Override
public Observable<Character> execute() {

    return mRepository.getCharacter(mCharacterId);
        // .awesomeRxStuff();
}
 
AvengerDetailPresenter буде нашим Observer в даному випадку буде тим хто піписується до подій надісланих Observable, це робиться за допомогою методу subscribe, що зв'язує Observer з Observable.
onNext та onError реалізовані для управління результатом операції. Метод onCompleted не реаалізований в даному випадку так як не є необхідним.

    mCharacterSubscription = mGetCharacterInformationUsecase
        .execute().subscribe(
            character   -> onAvengerReceived(character),
            error       -> manageError(error));

Retrofit & RxJava

Retrofit зі Square, RxJava підтримує методи типу rx. Observable так що запити можна робити за допомогою Observers редагувати та трансформувати.
Ви маєте бути на сторожі в залежності від того де використовується, Retrofit виконує запити в потоці де ваш Observable виходить, отже якщо ви будете його викликати в UI потоці (activity чи Fragment) отримаєте помилку.

Посилання










Source.

Комментариев нет:

Отправить комментарий