Während Sie sich nicht manuell von einem beendeten Stream abmelden müssen, können Sie dennoch mit RxJava2 ein Speicherleck erstellen, wenn Sie nicht vorsichtig sind.
Betrachten Sie den folgenden Code ein:
repository.getData()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> myTextView.setText(data.toString()));
Die Lambda-Parameter in der Zeichnung ist "syntaktischer Zucker" über eine anonyme innere Klasse:
subscribe(new Consumer<Data>() {
@Override
public void accept(final Data data) {
myTextView.setText(data.toString());
}
});
Auf der JVM eine anonyme innere Klasse unterhält einen Verweis auf die äußere Klasse.
Angenommen, für den obigen naiven Code ist die äußere Klasse eine Aktivität (dies würde auch für ein Fragment, Service, BroadcastReceiver oder jede Klasse folgen, deren Lebenszyklus vom Android OS gesteuert wird).
Die Aktivität abonniert den Observer, wird dann jedoch durch das Android-Betriebssystem unter Bedingungen mit geringem Arbeitsspeicher zerstört (Sie können diesen Effekt nachahmen, indem Sie Entwickleroptionen aktivieren/Aktivitäten nicht beibehalten). Wenn die Arbeit an Schedulers.io()
noch ausgeführt wird, wenn die Aktivität zerstört wird, wird weiterhin eine Referenz für die Aktivität über die anonyme innere Klasse verwaltet. Dies bedeutet ein Speicherleck, das verhindert, dass die Aktivität vom Garbage Collector abgeschlossen wird. Wenn die Aktivität eine Anzahl von Ansichten oder, sagen wir, ein Bitmap-Objekt aufweist, kann das Speicherleck ziemlich beträchtlich sein.
Es gibt eine Reihe von Lösungen, die hier aber einer von ihnen ist ein CompositeDisposable
Objekt zu erhalten und diese der Android-Aktivität im onDestroy()
Lifecycle-Methode zu löschen:
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();
}
}
Sie auf ein gutes Beispiel verweisen kann wie man RxJava in einer Android App im offiziellen Google Android Architecture Blueprints verwendet.