web-dev-qa-db-ja.com

完了したオブザーバブルの登録を解除する必要がありますか?

オブザーバブルが完了した場合でも、オブザーバーを削除する(メモリリークを防止する)ためにオブザーバブルをサブスクライブ解除/破棄(RxJava2で)する必要がありますか、またはonCompleteまたはonErrorイベントが発生?

SingleCompletableFlowableなどの他の型についてはどうでしょうか。

28
sockeqwe

はい。それで合っています。

ストリームが終了すると(onComplete/onErrorが呼び出された)、サブスクライバーは自動的にサブスクライブを解除します。 SubscriptionオブジェクトでisUnsubscribed()メソッドを使用して、これらの動作をテストできるはずです。

23
koperko

終了したストリームを手動でサブスクライブ解除する必要はありませんが、注意していない場合でも、RxJava2を使用してメモリリークを作成できます。

次のコードを検討してください。

_repository.getData()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(data -> myTextView.setText(data.toString()));
_

サブスクライブのラムダパラメータは、匿名の内部クラスに対する「syntatic sugar」です。

_subscribe(new Consumer<Data>() {
    @Override
    public void accept(final Data data) {
        myTextView.setText(data.toString());
    }
});
_

JVMでは、匿名の内部クラスが外部クラスへの参照を維持します。

上記の単純なコードの場合、外部クラスはアクティビティです(これは、フラグメント、サービス、BroadcastReceiver、またはAndroid OS)によって制御されるライフサイクルのクラスにも従います)。

アクティビティはObserverをサブスクライブしますが、Android OSがメモリ不足の状態の場合、OSによって破棄されます(開発者オプションをオンにすることでこの効果を模倣できます/アクティビティを保持しないでください)。アクティビティが破棄されてもSchedulers.io()での作業は引き続き実行されますが、匿名の内部クラスを通じてアクティビティへの参照が維持されます。これは、ガベージコレクターによるアクティビティのファイナライズを妨げるメモリリークを意味します。アクティビティに多数のビュー、またはたとえばビットマップオブジェクトがある場合、メモリリークはかなりの量になる可能性があります。

ここにはいくつかの解決策がありますが、その1つはCompositeDisposableオブジェクトを維持し、これをAndroidアクティビティのonDestroy()ライフサイクルメソッドでクリアすることです:

_public class MyActivity extends Activity {

   DataRepository dataRepository;
   CompositeDisposable disposables;

   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       disposables = new CompositeDisposable();
   }

   public void onButtonClick(View v) {
       repository.getData()             
          .subscribeOn(Schedulers.io())
          .observeOn(AndroidSchedulers.mainThread())
          .doOnSubscribe(disposable -> disposables.add(disposable))
          .subscribe(data -> myTextView.setText(data.toString()));
   }

   @Override
   public void onDestroy() {
       disposables.clear();
       super.onDestroy();
   }
}
_

Androidアプリ Google Androidアーキテクチャブループリント でRxJavaを使用する方法の良い例を参照できます。

8
David Rawson