Slide 1

Slide 1 text

RxJava modules potatotips #25 @petitviolet Fringe81 Co,. Ltd.

Slide 2

Slide 2 text

About Me • Hiroki Komurasaki • @petitviolet • Fringe81 Co,. Ltd • Scala Engineer • ちょっと前までAndroid

Slide 3

Slide 3 text

RxJava 使ってますか?

Slide 4

Slide 4 text

https://github.com/ReactiveX

Slide 5

Slide 5 text

Slide 6

Slide 6 text

RxJavaに色々と モジュールがあるので ちょっと触ってみた

Slide 7

Slide 7 text

RxJavaString https://github.com/ReactiveX/RxJavaString

Slide 8

Slide 8 text

private static void log(String msg) {
 Log.d(TAG, msg);
 } Observable toSplit = Observable.just("a,b,c");
 StringObservable
 .split(toSplit, ",")
 .subscribe(RxString::log);
 
 Observable toByLine = Observable.just("x\ny\nz\n");
 StringObservable
 .byLine(toByLine)
 .subscribe(RxString::log);
 // == StringObservable.split(toByLine, "\n")

Slide 9

Slide 9 text

private static void log(String msg) {
 Log.d(TAG, msg);
 } Observable toJoin = Observable.just("x", "y", "z");
 StringObservable
 .join(toJoin, ":")
 .subscribe(RxString::log);
 
 Observable toConcat = Observable.just("A", "B", "C");
 StringObservable
 .stringConcat(toConcat)
 .subscribe(RxString::log);
 // == StringObservable.join(toConcat, "")

Slide 10

Slide 10 text

文字列に関する便利機能 • Observableに対して文字列処理を簡単に 行えるようにするためのショートカット • InputStreamとかReaderも対象となる • encode/decodeもある

Slide 11

Slide 11 text

RxJavaMath https://github.com/ReactiveX/RxJavaMath

Slide 12

Slide 12 text

Observable src = Observable.just(1, 2, 3, 4, 5);
 MathObservable
 .averageInteger(src)
 .subscribe(RxMath::log);
 
 MathObservable
 .min(src)
 .subscribe(RxMath::log);
 
 MathObservable
 .max(src)
 .subscribe(RxMath::log);
 
 MathObservable
 .sumInteger(src)
 .subscribe(RxMath::log);

Slide 13

Slide 13 text

static class User {
 private final String name;
 private final String email;
 
 User(String name, String email) {
 this.name = name;
 this.email = email;
 }
 
 @Override
 public String toString() {
 return "User(" + name + ", " + email + ")";
 }
 } Observable users = Observable.just(
 new User("alice", "[email protected]"),
 new User("bob", "[email protected]"),
 new User("charley", "[email protected]")
 );
 MathObservable
 .from(users)
 .averageInteger(u -> u.email.length())
 .subscribe(RxMath::log); // 5 MathObservable
 .from(users)
 .max((u1, u2) -> u1.email.length() - u2.email.length())
 .subscribe(RxMath::log); // User(bob, [email protected])

Slide 14

Slide 14 text

数値に関する便利機能 • 平均・最大・最小を求めるためのショートカット • 独自のFunction1やComparatorを使える • fromでMathObservableに変換出来る

Slide 15

Slide 15 text

RxJavaDebug https://github.com/ReactiveX/RxJavaDebug

Slide 16

Slide 16 text

public static void debug(List list) {
 SimpleDebugNotificationListener listener = new SimpleDebugNotificationListener();
 DebugHook> hook = new DebugHook<>(listener);
 
 RxJavaPlugins.getInstance().registerObservableExecutionHook(hook);
 
 Observable.from(list)
 .flatMap(i -> Observable.from(Arrays.asList(i, i * 100)))
 .subscribe(integer -> {
 Log.d(TAG, "integer -> " + integer);
 });
 
 SortedSet> snapshot =
 listener.getNotificationsByObservable();
 
 Log.d(TAG, listener.toString(snapshot)); 
 } List list = Arrays.asList(1, 2, 3, 4, 5);
 debug(list);

Slide 17

Slide 17 text

public static void debug(List list) {
 SimpleDebugNotificationListener listener = new SimpleDebugNotificationListener();
 DebugHook> hook = new DebugHook<>(listener);
 
 RxJavaPlugins.getInstance().registerObservableExecutionHook(hook);
 
 Observable.from(list)
 .flatMap(i -> Observable.from(Arrays.asList(i, i * 100)))
 .subscribe(integer -> {
 Log.d(TAG, "integer -> " + integer);
 });
 
 SortedSet> snapshot =
 listener.getNotificationsByObservable();
 
 Log.d(TAG, listener.toString(snapshot)); 
 } List list = Arrays.asList(1, 2, 3, 4, 5);
 debug(list);

Slide 18

Slide 18 text

public static void debug(List list) {
 SimpleDebugNotificationListener listener = new SimpleDebugNotificationListener();
 DebugHook> hook = new DebugHook<>(listener);
 
 RxJavaPlugins.getInstance().registerObservableExecutionHook(hook);
 
 Observable.from(list)
 .flatMap(i -> Observable.from(Arrays.asList(i, i * 100)))
 .subscribe(integer -> {
 Log.d(TAG, "integer -> " + integer);
 });
 
 SortedSet> snapshot =
 listener.getNotificationsByObservable();
 
 Log.d(TAG, listener.toString(snapshot)); 
 } List list = Arrays.asList(1, 2, 3, 4, 5);
 debug(list);

Slide 19

Slide 19 text

public static void debug(List list) {
 SimpleDebugNotificationListener listener = new SimpleDebugNotificationListener();
 DebugHook> hook = new DebugHook<>(listener);
 
 RxJavaPlugins.getInstance().registerObservableExecutionHook(hook);
 
 Observable.from(list)
 .flatMap(i -> Observable.from(Arrays.asList(i, i * 100)))
 .subscribe(integer -> {
 Log.d(TAG, "integer -> " + integer);
 });
 
 SortedSet> snapshot =
 listener.getNotificationsByObservable();
 
 Log.d(TAG, listener.toString(snapshot)); 
 } List list = Arrays.asList(1, 2, 3, 4, 5);
 debug(list);

Slide 20

Slide 20 text

integer -> 1 integer -> 100 integer -> 2 integer -> 200 integer -> 3 integer -> 300 integer -> 4 integer -> 400 integer -> 5 integer -> 500 { "rx.Observable$27@225cfc95": [ {"ns_duration": 17179472, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "Subscribe", "source": "rx.Observable@18c8287c", "sourceFunc": "rx.Observable$2@15773505"}}, {"ns_duration": 127946, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "Request", "n": 9223372036854775807, "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 190474, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "1", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 51643, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "100", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 60648, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "2", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 31561, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "200", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 47015, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "3", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 51790, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "300", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 451663, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "4", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 404011, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "400", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 41103, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "5", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 72118, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "500", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 33840, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnCompleted", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 3058, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "Unsubscribe", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}} ], "rx.internal.operators.OperatorMerge$MergeSubscriber@26cb21aa": [ {"ns_duration": 7064, "threadId": 1, "notification": {"observer": "rx.internal.operators.OperatorMerge$MergeSubscriber@26cb21aa", "type": "OnStart", "to": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 16027011, "threadId": 1, "notification": {"observer": "rx.internal.operators.OperatorMerge$MergeSubscriber@26cb21aa", "type": "Request", "n": 9223372036854775807, "from": "rx.internal.operators.OperatorMap@2ecfd78b", "to": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 13054812, "threadId": 1, "notification": {"observer": "rx.internal.operators.OperatorMerge$MergeSubscriber@26cb21aa", "type": "OnNext", "value": "rx.Observable@2ad5068", "from": "rx.internal.operators.OperatorMap@2ecfd78b", "to": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 21963, "threadId": 1, "notification": {"observer": "rx.internal.operators.OperatorMerge$MergeSubscriber@26cb21aa", "type": "Request", "n": 1, "from": "rx.internal.operators.OperatorMap@2ecfd78b", "to": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 406769, "threadId": 1, "notification": {"observer": "rx.intern /(^o^)\

Slide 21

Slide 21 text

integer -> 1 integer -> 100 integer -> 2 integer -> 200 integer -> 3 integer -> 300 integer -> 4 integer -> 400 integer -> 5 integer -> 500 subscribeしたところ Observable.from(list)
 .flatMap(i -> Observable.from(Arrays.asList(i, i * 100)))
 .subscribe(integer -> {
 Log.d(TAG, "integer -> " + integer);
 });

Slide 22

Slide 22 text

{ "rx.Observable$27@225cfc95": [ {"ns_duration": 17179472, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "Subscribe", "source": "rx.Observable@18c8287c", "sourceFunc": "rx.Observable$2@15773505"}}, {"ns_duration": 127946, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "Request", "n": 9223372036854775807, "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 190474, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "1", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 51643, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "100", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 60648, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "2", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 31561, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "200", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 47015, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "3", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 51790, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "300", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 451663, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "4", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 404011, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "400", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 41103, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "5", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 72118, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "500", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 33840, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "OnCompleted", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}}, {"ns_duration": 3058, "threadId": 1, "notification": {"observer": "rx.Observable$27@225cfc95", "type": "Unsubscribe", "from": "rx.internal.operators.OperatorMerge@3cc7495a"}} ], DebugHookによって出されるログ

Slide 23

Slide 23 text

{"ns_duration": 17179472, "threadId": 1, "notification": { "observer": “rx.Observable$27@225cfc95", "type": "Subscribe", "source": "rx.Observable@18c8287c", "sourceFunc": “rx.Observable$2@15773505" } }, 一部抽出・拡大 {"ns_duration": 190474, "threadId": 1, "notification": { "observer": "rx.Observable$27@225cfc95", "type": "OnNext", "value": "1", "from": “rx.internal.operators.OperatorMerge@3cc7495a" } },

Slide 24

Slide 24 text

いろいろ情報が見れて便利 • Observerに対する以下が分かる • どのスレッドで • どのObservableの • どのonXXXから • どんな値が渡ってきているか • 注意点としてはObservableを作る前に設定を行うこと

Slide 25

Slide 25 text

RxJavaJoins https://github.com/ReactiveX/RxJavaJoins

Slide 26

Slide 26 text

Observable src_i = Observable.just(1, 2, 3, 4, 5);
 Observable src_s = Observable.just("a", "b", "c");
 Observable interval = Observable.interval(1, SECONDS);
 
 Plan0 plan =
 JoinObservable
 .from(src_i)
 .and(src_s)
 .and(interval)
 .then((i, s, l) -> i + ", " + s + ", " + l); 
 JoinObservable
 .when(plan)
 .toObservable()
 .subscribe(RxJoin::log); // 1, a, 0 // 2, b, 1 // 3, c, 2

Slide 27

Slide 27 text

Observable src_i = Observable.just(1, 2, 3, 4, 5);
 Observable src_s = Observable.just("a", "b", "c");
 Observable interval = Observable.interval(1, SECONDS);
 
 Observable.zip(
 src_i, src_s, interval,
 (i, s, l) -> i + ", " + s + ", " + l)
 .subscribe(RxJoin::log); // 1, a, 0 // 2, b, 1 // 3, c, 2 zip使っても書ける

Slide 28

Slide 28 text

Observableをまとめるやつ • zipでいいのでは • 違いがわからず • 流れるようなinterfaceで書けるのが利点? • and, then, when

Slide 29

Slide 29 text

まとめ • RxJavaはモジュール化されている • 特定の機能を持つモジュール群が存在 • 用途にあったものが実装されているかも • 今回紹介しなかったのも多数 • AsyncUtilとかParallelなんかも見えた