Rxandroid
RxAndroidは、Android向けに特別に記述されたRxJava拡張機能で、RxJavaを囲む特別なバインディングが含まれており、作業が楽になります。
まず、
AndroidSchedulers
      
      クラスがあります。これは、Android固有のスレッド用の既製のスケジューラーを提供します。 UIスレッドでコードを実行する必要がありますか? 問題ありません
AndroidSchedulers.mainThread()
      
      使用してください:
retrofitService.getImage(url) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(bitmap -> myImageView.setImageBitmap(bitmap));
独自の
Handler
      
      がある場合は、
HandlerThreadScheduler
      
      1を使用して関連するスケジューラを作成できます。
次に、Android SDKの一部のクラスにライフサイクル機能を提供する
AndroidObservable
      
      があります。
bindActivity()()
      
      および
bindFragment()
      
      演算子があります。これらの演算子は、自動的に
AndroidSchedulers.mainThread()
      
      を使用して監視するだけでなく、
Activity
      
      または
Fragment
      
      が作業を完了し始めたときにデータの生成を停止します(この方法では問題が発生しません。これができなくなったときに状態を変更しようとしています)。
 AndroidObservable.bindActivity(this, retrofitService.getImage(url)) .subscribeOn(Schedulers.io()) .subscribe(bitmap -> myImageView.setImageBitmap(bitmap));
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      AndroidObservable.fromBroadcast()
      
      も気に入っています。これにより、
BroadcastReceiver
      
      ように機能する
Observable
      
      を作成できます。 ここでは、たとえば、ネットワークステータスが変更されたときに通知を受け取ることができます。
 IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); AndroidObservable.fromBroadcast(context, filter) .subscribe(intent -> handleConnectivityChange(intent));
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      最後に、
View
      
      バインディングを追加する
ViewObservable
      
      があり
View
      
      。 特に、
View
      
      が
ViewObservable.text()
      
      されるたびに通知する場合は
ViewObservable.clicks()
      
      ステートメント、および
TextView
      
      がコンテンツを変更するたびに
ViewObservable.text()
      
      が含まれます。
 ViewObservable.clicks(mCardNameEditText, false) .subscribe(view -> handleClick(view));
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      後付け
Android用の人気のあるRESTクライアントであるRetrofitとして、RxJavaをサポートする注目すべきライブラリがあります。 通常、その中で非同期メソッドを定義するときは、
Callback
      
      を使用します:
 @GET("/user/{id}/photo") void getUserPhoto(@Path("id") int id, Callback<Photo> cb);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      ただし、RxJavaを使用する場合は、代わりに友人の
Observable
      
      返すことができます。
 @GET("/user/{id}/photo") Observable<Photo> getUserPhoto(@Path("id") int id);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      その後、必要に応じてすぐに
Observable
      
      を使用できます
Observable
      
      からデータを取得できるだけでなく、その場で変換することもできます。
Observable
      
      含まれる
Observable
      
      サポートにより、複数のRESTリクエストを簡単に組み合わせることができます。 たとえば、2つのAPIメソッドがあり、1つ目は写真を返し、2つ目はそのメタデータを返します。 これらのクエリの結果を一緒に収集できます。
Observable.zip( service.getUserPhoto(id), service.getPhotoMetadata(id), (photo, metadata) -> createPhotoWithData(photo, metadata)) .subscribe(photoWithData -> showPhoto(photoWithData));
2番目の部分で似たようなことを示しました(
flatMap()
      
      を使用)。 ここで、RxJava + Retrofitバンドルを使用して複数のRESTリクエストを1つにまとめることがいかに簡単かを示したいと思いました。
古い、遅いコード
Retrofitが
Observables
      
      を返すことができるという事実は素晴らしいですが、それらについて何も聞いていない別のライブラリがある場合はどうでしょうか。 または、
Observable
      
      動作するように、手間をかけずに変更したい古いコードがありますか。 簡単に言えば、すべてを書き直さずに、古いコードと新しいコードをどのように組み合わせるのでしょうか?
ほとんどの場合、
Observable.just()
      
      および
Observable.from()
      
      を使用するだけで十分です。
 private Object oldMethod() { ... } public Observable<Object> newMethod() { return Observable.just(oldMethod()); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      oldMethod()
      
      が高速の場合、これはうまく機能しますが、そうでない場合はどうなりますか?
oldMethod()
      
      が
oldMethod()
      
      に呼び出され、その結果のみが
Observable.just()
      
      渡されるため、スレッド全体をブロックします。
この問題を回避するには、次のトリックを使用できます(私は常に使用しています):
Observable.defer()
      
      で遅いコードをラップします。
 private Object slowBlockingMethod() { ... } public Observable<Object> newMethod() { return Observable.defer(() -> Observable.just(slowBlockingMethod())); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      これで、受け取った
Observable
      
      は、サブスクライブするまで
slowBlockingMethod()
      
      呼び出しません。
ライフサイクル
私は最後に最も難しい部分を残しました。 RxJavaを使用する場合、
Activity
      
      ライフサイクルをどのように考慮しますか? 何度も繰り返し感じられる問題がいくつかあります。
-  構成の変更後にサブスクリプションを再開します。 
      
 
 たとえば、Retrofitを使用してRESTリクエストを作成し、その結果をListView
 
 
 
 に表示したいとします。 リクエストの実行中にユーザーが電話を回したらどうなりますか? リクエストの実行を再開する必要がありますが、どのように?
-   Context
 
 
 
 への参照を保持するObservables
 
 
 
 によって引き起こされるメモリリーク。
 
 この問題は、Context
 
 
 
 へのリンクを何らかの形で保持するサブスクリプションを作成することによって発生します(Views
 
 
 
 場合はそれほど難しくありません!)Observable
 
 
 
 が時間通りに作業を終了しない場合、ある時点で、多くのメモリを解放できます。
残念ながら、ここには特効薬はありませんが、あなたの人生を単純化できるテクニックがいくつかあります。
最初の問題は、RxJavaの組み込みキャッシュメカニズムを使用して処理できます。これにより、同じ
Observable
      
      サブスクライブ/サブスクライブ解除できます。 具体的には、
cache()
      
      (または
replay()
      
      )は、購読を解除できた場合でも、以前に実行されたリクエストを継続します。 これは、
Activity
      
      再作成した後も引き続き作業できることを意味します。
 Observable<Photo> request = service.getUserPhoto(id).cache(); Subscription sub = request.subscribe(photo -> handleUserPhoto(photo)); // ... Activity ... sub.unsubscribe(); // ...  Activity  ... request.subscribe(photo -> handleUserPhoto(photo));
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      両方のケースで同じキャッシュされた
request
      
      を使用することに注意してください。 したがって、彼が実行するクエリは1回だけ実行されます。
request
      
      を保存する場所はあなた次第ですが、ライフサイクルに関連するすべての決定と同様に、これはライフサイクルによって生成される変更(保持されたフラグメント、シングルトンなど)を受ける場所でなければなりません。
2番目の問題は、ライフサイクルに従ってサブスクリプションのサブスクリプションを正しく解除することで解決されます。 一般的な解決策は、
CompositeSubscription
      
      を使用してすべてのサブスクリプションを保存し、それらをすべて
onDestroy()
      
      または
onDestroy()
      
      で
onDestroy()
      
      解除することです。
 private CompositeSubscription mCompositeSubscription = new CompositeSubscription(); private void doSomething() { mCompositeSubscription.add( AndroidObservable.bindActivity(this, Observable.just("Hello, World!")) .subscribe(s -> System.out.println(s))); } @Override protected void onDestroy() { super.onDestroy(); mCompositeSubscription.unsubscribe(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      生活を簡素化するために、
CompositeSubscription
      
      を含む基本的な
Activity
      
      /
Fragment
      
      を作成できます。これにより、後ですべてのサブスクリプションを保存し、自動的にクリアされます。
注意!
CompositeSubscription.unsubscribe()
      
      を呼び出すとすぐに、
CompositeSubscription.unsubscribe()
      
      このインスタンスは使用できなくなります(つまり、もちろんサブスクリプションを追加できますが、すぐに
unsubscribe()
      
      を呼び出します!) 今後も
CompositeSubscription
      
      を引き続き使用する場合は、新しいインスタンスを作成する必要があります。
これらの問題の両方を解決するために、追加のコードを書くことを余儀なくされています。そのため、いつか待ち望んでいた天才が天から降りてきて、これをすべて簡素化する方法を見つけてくれることを本当に願っています。
結論は?
RxJavaは比較的新しい技術であり、Androidの場合はさらに新しいため、これまでのところAndroidの結論はありません。 RxAndroidは活発に開発されており、私たち(Androidプログラマー)はまだ良い方法と悪い方法を見つけようとしています。 RxJava + RxAndroidバンドルの優れた使用の一般に認められた例はまだありません。1年後、ここでお伝えしたヒントのいくつかはかなり風変わりなものと見なされるでしょう。
それまでの間、RxJavaはコードの記述プロセスを単純化するだけでなく、それをもう少し面白くすることがわかりました。 それでも私を信じないなら、いつか会ってビールのグラスでそれについて話しましょう。
Matthias Kayにこの記事の準備に非常に貴重な助けをしてくれたことに改めて感謝し、 RxAndroidをさらにクールにするためにみんなに参加することをお勧めします!
1
AndroidSchedulers.mainThread()
      
      は、
HandlerThreadScheduler
      
      使用します。
ご注意 翻訳者: Artem_zinに 、私が問題を引き起こしたいくつかの場所の翻訳を手伝ってくれたことに感謝します。 彼とRxJavaに関する彼の広範な知識がなければ、私は長い間立ち往生するでしょう。