Benutzerdefinierte Operatoren in RxJava implementieren

Benutzerdefinierte Operatoren in RxJava implementieren

1. Überblick

In diesem kurzen Tutorial zeigen wir, wie Sie einen benutzerdefinierten Operator mitRxJava schreiben.

Wir werden diskutieren, wie dieser einfache Operator sowie ein Transformator aufgebaut werden - sowohl als Klasse als auch als einfache Funktion.

2. Maven-Konfiguration

Zuerst müssen wir sicherstellen, dass wir die Abhängigkeit vonrxjavainpom.xml haben:


    io.reactivex
    rxjava
    1.3.0

Wir können die neueste Version vonrxjava aufMaven Central überprüfen.

3. Benutzerdefinierter Operator

We can create our custom operator by implementing Operator interface, im folgenden Beispiel haben wir einen einfachen Operator zum Entfernen nicht alphanumerischer Zeichen ausString implementiert:

public class ToCleanString implements Operator {

    public static ToCleanString toCleanString() {
        return new ToCleanString();
    }

    private ToCleanString() {
        super();
    }

    @Override
    public Subscriber call(final Subscriber subscriber) {
        return new Subscriber(subscriber) {
            @Override
            public void onCompleted() {
                if (!subscriber.isUnsubscribed()) {
                    subscriber.onCompleted();
                }
            }

            @Override
            public void onError(Throwable t) {
                if (!subscriber.isUnsubscribed()) {
                    subscriber.onError(t);
                }
            }

            @Override
            public void onNext(String item) {
                if (!subscriber.isUnsubscribed()) {
                    final String result = item.replaceAll("[^A-Za-z0-9]", "");
                    subscriber.onNext(result);
                }
            }
        };
    }
}

Im obigen Beispiel müssen wir überprüfen, ob der Abonnent abonniert ist, bevor wir unsere Operation anwenden und den Artikel an ihn senden, da dies nicht erforderlich ist.

We are also restricting instance creation only to static factory methods to achieve a more user-friendly readability beim Verketten von Methoden und beim statischen Import.

Und jetzt können wir den Operatorliftverwenden, um unseren benutzerdefinierten Operator einfach mit anderen Operatoren zu verketten:

observable.lift(toCleanString())....

Hier ist ein einfacher Test unseres benutzerdefinierten Operators:

@Test
public void whenUseCleanStringOperator_thenSuccess() {
    List list = Arrays.asList("john_1", "tom-3");
    List results = new ArrayList<>();
    Observable observable = Observable
      .from(list)
      .lift(toCleanString());
    observable.subscribe(results::add);

    assertThat(results, notNullValue());
    assertThat(results, hasSize(2));
    assertThat(results, hasItems("john1", "tom3"));
}

4. Transformator

Wir können unseren Operator auch erstellen, indem wir die Schnittstelle vonTransformerimplementieren:

public class ToLength implements Transformer {

    public static ToLength toLength() {
        return new ToLength();
    }

    private ToLength() {
        super();
    }

    @Override
    public Observable call(Observable source) {
        return source.map(String::length);
    }
}

Beachten Sie, dass wir den TransformatortoLength verwenden, um unser beobachtbares Element vonString in seine Länge inInteger umzuwandeln.

Wir benötigen einencompose-Operator, um unseren Transformator verwenden zu können:

observable.compose(toLength())...

Hier ist ein einfacher Test:

@Test
public void whenUseToLengthOperator_thenSuccess() {
    List list = Arrays.asList("john", "tom");
    List results = new ArrayList<>();
    Observable observable = Observable
      .from(list)
      .compose(toLength());
    observable.subscribe(results::add);

    assertThat(results, notNullValue());
    assertThat(results, hasSize(2));
    assertThat(results, hasItems(4, 3));
}

Daslift(Operator)arbeitet mit den Abonnenten von Observable, abercompose(Transformer)arbeitet mit dem Observable selbst.

Wenn wir unseren benutzerdefinierten Operator erstellen, sollten wirTransformer auswählen, wenn wir das Observable als Ganzes bearbeiten möchten, undOperator auswählen, wenn wir die vom Observable emittierten Elemente bearbeiten möchten

5. Benutzerdefinierter Operator als Funktion

Wir können unseren benutzerdefinierten Operator als Funktion anstelle vonpublic class implementieren:

Operator cleanStringFn = subscriber -> {
    return new Subscriber(subscriber) {
        @Override
        public void onCompleted() {
            if (!subscriber.isUnsubscribed()) {
                subscriber.onCompleted();
            }
        }

        @Override
        public void onError(Throwable t) {
            if (!subscriber.isUnsubscribed()) {
                subscriber.onError(t);
            }
        }

        @Override
        public void onNext(String str) {
            if (!subscriber.isUnsubscribed()) {
                String result = str.replaceAll("[^A-Za-z0-9]", "");
                subscriber.onNext(result);
            }
        }
    };
};

Und hier ist der einfache Test:

List results = new ArrayList<>();
Observable.from(Arrays.asList("[email protected]", "or-an?ge"))
  .lift(cleanStringFn)
  .subscribe(results::add);

assertThat(results, notNullValue());
assertThat(results, hasSize(2));
assertThat(results, hasItems("apple", "orange"));

Ähnliches gilt für das Beispiel vonTransformer:

@Test
public void whenUseFunctionTransformer_thenSuccess() {
    Transformer toLengthFn = s -> s.map(String::length);

    List results = new ArrayList<>();
    Observable.from(Arrays.asList("apple", "orange"))
      .compose(toLengthFn)
      .subscribe(results::add);

    assertThat(results, notNullValue());
    assertThat(results, hasSize(2));
    assertThat(results, hasItems(5, 6));
}

6. Fazit

In diesem Artikel haben wir gezeigt, wie unsere RxJava-Operatoren geschrieben werden.

Und wie immer kann der vollständige Quellcodeover on GitHub gefunden werden.