Sometimes it is necessary to do a cleanup on the internal resources that were used to feed Emitter when an Observable completes. Consider this example where we will click events from a View:
Observable.create(emitter -> {
helloText.setOnClickListener(v -> emitter.onNext(v));
});
This Observable never completes but even if it terminates, there is still a problem present--the reference to the Emitter (and thus Observable) will alway be present because the following call created a ClickListener that never went away:
helloText.setOnClickListener(v -> emitter.onNext(v));
So, the ClickListener always has a reference to the Emitter, and Emitter has a reference to the Observable. The memory will never be freed up, and the setOnClickListener() listener will keep calling:
v -> emitter.onNext(v)
To fix this, we need to add a Cancellable action with this:
emitter.setCancellable(() -> helloText.setOnClickListener(null));
This way, the listener on TextView will be cleaned up. This method can be used to clean up other kinds of resources, such as these:
- Closing files
- Closing remote socket connections
- Terminating threads
- Others
So, now the block with clean up code can look as follows:
Observable.create(emitter -> {
emitter.setCancellable(() -> helloText.setOnClickListener(null));
helloText.setOnClickListener(v -> emitter.onNext(v));
})
In this particular case, since we are working with Views, it is advised to use MainThreadDisposable from the RxAndroid library. Consider the following example:
Observable.create(emitter -> {
emitter.setDisposable(new MainThreadDisposable() {
@Override
protected void onDispose() {
helloText.setOnClickListener(null);
}
});
helloText.setOnClickListener(v -> emitter.onNext(v));
})
This way, the interaction with the TextView will happen on the main Android UI thread. Also, in this case, we've used the .setDisposable() method; it serves the same purpose as .setCancellable() but is used in cases where the Disposable interface is already available from somewhere else.