android meets rxjava - 渋谷java#6

26
Android meets RxJava 渋谷Java #6 @yo_waka

Upload: yowaka

Post on 10-May-2015

2.860 views

Category:

Technology


2 download

DESCRIPTION

渋谷Java#6 で発表した資料です。

TRANSCRIPT

Page 1: Android meets RxJava - 渋谷Java#6

Android meets RxJava渋谷Java #6 @yo_waka

Page 2: Android meets RxJava - 渋谷Java#6

freeeという会計サービスの会社でAndroid/iOSアプリを作っています

初めまして@yo_waka 若原 祥正

本当はJavaScriptが好き

Page 3: Android meets RxJava - 渋谷Java#6

まさか複数回OOMの話しが出るようなガチなイベントだと思っ

ていませんでした><

Page 4: Android meets RxJava - 渋谷Java#6

Androidでめんどくさいこと

• 非同期なAPIを複数叩いて全て結果が揃うのを待ったり、エラー処理は1つにまとめたり

• 複数の入力値を組み合わせてチェック • これらのテスト。。。

Page 5: Android meets RxJava - 渋谷Java#6

愚直に書くとしんどいし 愚直に書くとクソコードに なりやすいところ

Page 6: Android meets RxJava - 渋谷Java#6

Androidで非同期処理の結果や 何らかの入力値のチェックを

Streamぽくシンプルに統一的に書きたい

Page 7: Android meets RxJava - 渋谷Java#6

RxJavaNetflix社が公開している

Reactive Extension

Page 8: Android meets RxJava - 渋谷Java#6

Functional Reactive Programming

については時間ないのでノータッチで

Page 9: Android meets RxJava - 渋谷Java#6

From Future to Observable

Futureは入れ子になった非同期処理の扱いがムズい、またそれぞれの結果の条件で処理を変えるとかしようとするとムズい。 (同期/非同期混じるとさらにムズい)

Page 10: Android meets RxJava - 渋谷Java#6

From Future to Observable

Observableな結果オブジェクトのフィルタ、選択、変換、結合、合成を行えるオペレーターのコレクションによって、同期/非同期を意識することなく扱えるようにする

!注)java.util.Observableではなく、rx.Observableです

Page 11: Android meets RxJava - 渋谷Java#6

Observableを返すAPI設計にすることで、様々な処理が統一的に書けるようになる

Page 12: Android meets RxJava - 渋谷Java#6

基本フロー

Observable

Publisher Observer

#create

Observable.OnSubscribe<T>#call

#subscribe

#onNext #onError #onCompleted

Observer

#call

Page 13: Android meets RxJava - 渋谷Java#6

基本フロー + 結果をフィルタ

Observable

Publisher Observer

#create

Observable.OnSubscribe<T>#call

#subscribe

#onNext #onError #onCompleted

Observer Func

#call

FailureSuccess

Page 14: Android meets RxJava - 渋谷Java#6

基本フロー + 間に処理を挟む

Observable

Publisher Observer

#create

Observable.OnSubscribe<T>#call

#subscribe

#onNext #onError #onCompleted

Observer Action

#call

Page 15: Android meets RxJava - 渋谷Java#6

Observer、Subscriber、Func、Action

全てObservableなので再利用しやすい

!A->B、C->B、D->A->C みたいな場合、 無名クラスにしなければ再利用可能

Page 16: Android meets RxJava - 渋谷Java#6

具体例

Page 17: Android meets RxJava - 渋谷Java#6

認証とユーザー情報をまとめるpublic Observable<String> login(JsonObject params) { return http.request( Request.Method.POST, API_LOGIN_URL, params ).map(new LoginFunc()).flatMap(new Func1<Token, Observable<String>>() { @Override public Observable<String> call(Token token) { return http.request( Request.Method.GET, API_USER_INFO_URL, null ); } });}!public class LoginFunc implements Func1<String, Token> { @Override public Token call(String jsonResponse) { Gson gson = GsonFactory.getSimpleInstance(); Token token = gson.fromJson(jsonResponse, Token.class); // トークンのキャッシュとか! return token;  }}

レスポンスを モデルに変換

別のObservableを直列にMapする

Page 18: Android meets RxJava - 渋谷Java#6

使う側は処理を1つ書くだけ// Fragmentなどで viewModel.login(params).subscribe(new Observer<String>() { @Override public void onCompleted() {}! @Override public void onError(Throwable throwable) { // エラー処理 }! @Override public void onNext(String s) { // メインアクティビティへ遷移 startActivity(new Intent(getActivity(), MainActivity.class)); getActivity().finish(); }});

どのリクエストでエラーが 起きてもここに到達する

Page 19: Android meets RxJava - 渋谷Java#6

自作のObservableを作るpublic static Observable<String> text(TextView view) { String currentText = String.valueOf(view.getText()); final BehaviorSubject<String> subject = BehaviorSubject.create(currentText);! view.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {}! @Override public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {}! @Override public void afterTextChanged(Editable editable) { subject.onNext(editable.toString()); } });! return subject;}

入力値変更時にonNextを呼ぶ

Page 20: Android meets RxJava - 渋谷Java#6

入力値によってメニューボタンを enabled/disabledにする

Observable.combineLatest( MyObservable.text(dateInput), MyObservable.text(amountInput), new Func2<String, String>() { @Override public Boolean call(String issueDateStr, String amountStr) { long amount = NumberUtils.safeLongValueFromString(amountStr); return !Strings.isNullOrEmpty(issueDateStr) && amount > 0; } }).subscribe(new Action1<Boolean>() { @Override public void call(Boolean enabled) { menuButton.setEnabled(enabled); }});

TextInputをObservableに してシリアル連結

最後のFunc#callの返り値が引数として渡る

ここまでの結果がそれぞれ引数として入ってくる

Page 21: Android meets RxJava - 渋谷Java#6

テストもシンプルに書ける

dateInput.setText(“2014/05/31”);amountInput.setText(null);!assertThat(menuButton).isDisabled();!amountInput.setText(“50000”);!// 特にイベント発火やメソッド分割する手間もいらないassertThat(menuButton).isEnabled();

Page 22: Android meets RxJava - 渋谷Java#6

RxJava-Android

Observer、Subscriberそれぞれどのスレッドで実行するかを選択できる(重要!)。

// 別スレッドでSubscriberを実行observer.subscribeOn(Schedulers.newThread());!// メインスレッドでObserverを実行observer.observeOn(AndroidSchedulers.mainThread());

Page 23: Android meets RxJava - 渋谷Java#6

使ってみて

• 学習コストは高いけど慣れてきて上手くコンポーネント化できると楽しい

• 閲覧だけのシンプルなアプリならEventBusでもいいかも

• ちょっと複雑な入力系のアプリならおすすめ

Page 24: Android meets RxJava - 渋谷Java#6

Reactive周りが熱い

Reactive Stream  JVM上のノンブロッキングなストリーム処理を標準化するプロジェクト  最終的にJSRでの標準化を目指してるらしい

 Typesafe社を中心としてJVMの非同期処理周りのメインプレーヤーが勢揃いしているぽい  RxJavaの作者も入ってる

Page 25: Android meets RxJava - 渋谷Java#6

せっかくなので宣伝

6月から五反田にオフィス移転するので、Android/

Gradleとかモバイルトークしたい方いればいつでも遊びに来てください! ※ 20時前後くらいに来るとご飯食べられるらしいです

Page 26: Android meets RxJava - 渋谷Java#6

ありがとうございました