Si un observable se termine, dois-je tout de même me désinscrire/supprimer (dans RxJava2) l'observable pour supprimer l'observateur (éviter les fuites de mémoire) ou est-ce géré en interne par RxJava une fois un onComplete
ou onError
l'événement se produit?
qu'en est-il des autres types comme Single
, Completable
, Flowable
etc.
Oui vous avez raison.
Après la fin d'un flux (onComplete/onError a été appelé), l'abonné se désabonne automatiquement. Vous devriez pouvoir tester ces comportements à l'aide de la méthode isUnsubscribed()
sur l'objet Subscription.
Bien que vous n'ayez pas besoin de vous désabonner manuellement d'un flux terminé, vous pouvez toujours créer une fuite de mémoire à l'aide de RxJava2 si vous ne faites pas attention.
Considérez le code suivant:
repository.getData()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> myTextView.setText(data.toString()));
Le paramètre lambda dans l'abonnement est "sucre syntaxique" sur une classe interne anonyme:
subscribe(new Consumer<Data>() {
@Override
public void accept(final Data data) {
myTextView.setText(data.toString());
}
});
Sur la machine virtuelle Java, une classe interne anonyme conserve une référence à la classe externe.
Supposons que pour le code naïf ci-dessus, la classe externe est une activité (cela suivrait également pour un fragment, un service, un BroadcastReceiver ou toute classe dont le cycle de vie est contrôlé par le système d'exploitation Android).
L'activité s'abonne à l'observateur mais est ensuite détruite par le système d'exploitation Android dans des conditions de faible mémoire (vous pouvez imiter cet effet en activant les options du développeur/ne pas conserver les activités). Si le le travail sur Schedulers.io()
est toujours en cours d'exécution lorsque l'activité est détruite, une référence sera toujours maintenue à l'activité via la classe interne anonyme. Cela signifie une fuite de mémoire qui empêche l'activité d'être finalisée par le garbage collector. Si l'activité a un certain nombre de vues ou, par exemple, un objet Bitmap, la fuite de mémoire peut être assez importante.
Il existe un certain nombre de solutions ici, mais l'une d'elles consiste à conserver un objet CompositeDisposable
et à l'effacer dans la méthode de cycle de vie onDestroy()
de l'activité Android :
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();
}
}
Vous pouvez vous référer à un bon exemple de la façon d'utiliser RxJava dans une application Android dans l'officiel Google Android Blueprints d'architecture ).