rxjava on android
DESCRIPTION
RxJava NightのLTで発表した資料です。TRANSCRIPT
RxJava on Android2014/10/28 @yo_waka
はじめまして
@yo_waka
若原 祥正
• freeeという会計サービスの会社でAndroid/iOSアプリを作っています
ちょっとだけ宣伝
• 個人事業主の確定申告、小規模法人の決算をもっとカンタンに
• PC,モバイルはこだわらず、どこでもどのデバイスでも帳簿をつけられるよ
RxJavaの使いどころ• MVVMのつなぎとして使っています
• FragmentからViewの状態変更を監視してコールバック実行
• ViewModelからAPIリクエストの結果をFragmentに返す
• ViewModelの状態をFragmentに反映させる !
• それぞれのインターフェースをObservableで統一
RxJavaでMVVM
ViewModel ModelActivity/Fragment
CustomView API Client
ObservableObservable
Observable
API Client• APIを叩いた結果をObservableで返す
protected Observable<String> request(final int method, final String path) { return Observable.create(new RequestSubscriber(method, path)) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()); } // Observable.OnSubscribeを実装したクラスはObservableにできる public class RequestSubscriber implements Observable.OnSubscribe<String> { @Override public void call(final Subscriber<? super String> subscriber) { // リクエストのコールバックで // subscriber.onNext(string), subscriber.onCompleted() を呼ぶ } }
ViewModel• APIクライアントの結果を処理するObservableを返す
public Observable<Item> getItems(String name) { return apiClient.request(Request.Method.POST, API_URL) .map(new GettingItemFunc()) /* doOnNextの前に処理を挟む */ .doOnError(new ErrorHandler()); /* エラー処理 */ } // callメソッドに渡す引数の数に応じて、Func0~Nまであるよ! private class GettingItemsFunc implements Func1<String, List<Item>> { @Override public List<Item> call(String jsonResponse) { Gson gson = GsonFactory.getInstance(); itemList = gson.fromJson(jsonResponse, ItemList.class); } }
Fragment• APIクライアントの結果を処理するObservableを返す
public Observable<Item> getItems(String name) { return apiClient.request(Request.Method.POST, API_URL) .map(new GettingItemFunc()) /* doOnNextの前に処理を挟む */ .doOnError(new ErrorHandler()); /* エラー処理 */ } private class GettingItemsFunc implements Func1<String, List<Item>> { @Override public List<Item> call(String jsonResponse) { Gson gson = GsonFactory.getInstance(); itemList = gson.fromJson(jsonResponse, ItemList.class); } }
RxAndroidについて
RxAndroid• RxJavaのAndroid向けバインディングを提供してくれるライブラリ
• RxJavaと時を同じくしてio.reactivexに移った
• Undocumented!!
compile 'io.reactivex:rxandroid:0.22.0'
実行スレッドの指定• SubscriberとObserverの実行スレッドを指定できる (AndroidSchedulerというユーティリティも提供)
• APIコールなど非同期処理をSubscribeする場合はこいつで
Observable.from("one", "two", "three", "four", "five") .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(/* an Observer */);
ハマりどころ
• Activity, Fragment上で実行する場合は注意が必要
• Subscriber実行中に画面回転などが起きると、Fragmentが破棄された状態でコールバックが実行されてNullPointerExceptionが起きがち
• 気にしていても忘れがちなので何とかしたい
Activity,Fragmentの バインディング
• 実行前にactivity.isFinishing()、fragment.isAdded()をチェック
• ライフサイクルを気にせずObserveできて便利
AndroidObservable.bindFragment( // bindActivityもあるよ this, viewModel.getList() ) .subscribeOn(Schedulers.io()) .subscribe(/* an Observer */); // 自動でmainThreadで実行
便利なOperator• OperatorConditionalBinding便利条件付きObserverをカンタンに作れるfalseが返された時は自動でunsubscribe()も呼ばれて素敵
public class Validator implements Func1<SomeClass, Boolean>() { @Override public Boolean call(SomeClass obj) { return obj.isValid(); } }; viewModel.createNew() .subscribe(new Observer<List<Deal>>() { /** do something */ }) .lift(new OperatorConditionalBinding<T, SomeClass>( new SomeClass(), new Validator() ));
便利なOperator• ViewObservableでView,TextView,AdapterViewなどのイベントをバインドできる
ViewObservable.clicks(view, false).subscribe(new Observer<OnClickEvent>() { @Override public void onNext(OnClickEvent evt) {} }); ViewObservable.text(inputView, false) .delay(1000, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) // これを忘れると動かない .subscribe(new Observer<String>() { @Override public void onNext(String s) {} }); ViewObservable.itemClicks(adapter, false).subscribe(new Observer<OnItemClickEvent>() { @Override public void onNext(OnItemClickEvent evt) {} });
まとめ• RxAndroidはAndroidでRxJavaのお供に特にAndroidSchedulerは便利
• 用意されているOperatorは便利だけど実装小さいので自分で作るのと大して変わらない
• クラスファイルはどれも小さいので自前のRx実装の参考にもしやすい
• ドキュメントは無いけど
ありがとうございました