Generation of call chain
For example, fragment inherits RxFragment from RxLifecycle and then initiates network requests in fragment
// observable generated by Retrofit
Retrofit.create(xxx).subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(fragment.bindUntilEvent(FragmentEvent.DETACH))
.subscribe(new Observer<Response<T>>() {
@Override
public void onError(Throwable e) {
onResponseError(e);
}
@Override
public void onComplete() {
// do something
}
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Response<T> t) {
onResponse(t);
}
});
The generated call chain is as follows
this = {ObservableTakeUntil@14202}
other = {ObservableFilter@14199}
predicate = {RxLifecycle$1@14208}
event = {FragmentEvent@14227} "DETACH"
source = {BehaviorSubject@14209}
source = {ObservableObserveOn@14193}
scheduler = {HandlerScheduler@14188}
source = {ObservableUnsubscribeOn@14187}
scheduler = {IoScheduler@14181}
source = {ObservableSubscribeOn@14180}
scheduler = {IoScheduler@14181}
source = {CallExecuteObservable@14166}
Call of key methods
According to the generated call chain, the last subscribe called is the ObservableTakeUntil.subscribe() method, whose subscribeActual() method is as follows
@Override
public void subscribeActual(Observer<? super T> child) {
final SerializedObserver<T> serial = new SerializedObserver<T>(child);
final ArrayCompositeDisposable frc = new ArrayCompositeDisposable(2);
final TakeUntilObserver<T> tus = new TakeUntilObserver<T>(serial, frc);
child.onSubscribe(frc);
other.subscribe(new TakeUntil(frc, serial));
source.subscribe(tus);
}
Here the other is ObservableFilter, the source is ObservableObserveOn. In the call to other/source.subscribe(), onSubscribe() is called in BehaviorSubject/ObservableSubscribeOn.subscribeActual(), respectively, and eventually to TakeUntil/TakeUnObserver.onSubscribe(), where frc is assigned. After assignment, frc is as follows
this = {ArrayCompositeDisposable@6850}
array = {Object[2]@6871}
0 = {ObservableObserveOn$ObserveOnObserver@6862} "0"
1 = {ObservableFilter$FilterObserver@6852}
The call of dispose
Two paths are called to dispose
ObservableTakeUntil.subscribeActual
ObservableFilter.subscribeActual
BehaviorSubject.subscribeActual
BehaviorSubject$BehaviorDisposable.emitFirst
// After that, it's the real dispose process.
BehaviorSubject$BehaviorDisposable.test
NotificationLite.accept
ObservableFilter$FilterObserver.onNext
ObservableTakeUntil$TakeUntil.onNext // Here, while calling dipose, onCompete is also called to notify observer.
ArrayCompositeDisposable.dispose
// Here we traverse frc and dispose
ObservableObserveOn$ObserveOnObserver.dispose
ObservableUnsubscribeOn$UnsubscribeObserver.dispose // Set the AtomicBoolean flag to true to indicate dispose
ObservableSubscribeOn$SubscribeOnObserver.dispose
DisposableHelper.dispose
CallExecuteObservable.dispose // Call okHttpCall.cancel
DisposableHelper.dispose
scheduler.dispose
ObservableFilter$FilterObserver
BasicFuseableObserver.dispose
BehaviorSubject$BehaviorDisposable.dispose // cancel is set to true
Fragment.onDetach
BehaviorSubject.onNext(FragmentEvent.DETACH)
BehaviorSubject$BehaviorDisposable.emitNext
// This is the true dispose process after that, ibid.
BehaviorSubject$BehaviorDisposable.test
The above different observer s have disposed, the specific dispose is different, such as terminating okHttpCall, terminating scheduler, setting identification bits and so on.
If:
1. dispose before the request is made, and go to the first branch, because okHttpCall is cancel ed, so it will not make the request again.
2. After the request is made, dispose will go to the second branch, because Observable Unsubscribe On $Unsubscribe Observer has dispose, get() == true, so onNext will not do anything here, as follows
@Override
public void onNext(T t) {
if (!get()) {
actual.onNext(t);
}
}
Because the call is terminated and cleaned up in dispose and onComplete is also called, there will be no memory leak and no callback to Activity/Fragment, resulting in possible null pointer and other exceptions.
summary
Two key points are:
1. Observable TakeUntil is generated. In addition to source, other is generated. Other defines behavior according to predicate (condition). That is, when predicate.test is true, it executes the method of calling Observer Filter Observer through behavior 2. Observable TakeUntil $TakeUntil. onNext is actually called again by Observable Filter Observer, which is entered through frc. dispose
Bug:
A small problem with RxLifecycle.
When compose
1. If the until event is FragmentEvent.DESTROY_VIEW, the request for fragment s is sent after onDestoryView, which can cause problems. Reason: BehaviorSubject$BehaviorDisposable.emitNext will not be invoked at onDestoryView because the request has not yet been sent and the queue is empty, and then the DESTROY_VIEW event is washed out by the subsequent DESTROY and DETACH events in turn, so the request will not be cancelled when the request returns because the event is not DESTROY_VIEW, and the callback of the final request will still be invoked. use
2. If the until event is FragmentEvent.DETACH, then the problem also occurs when the request result is returned between onDestoryView and onDetach.
In general, it is better to set the until event to DESTROY_VIEW, and then remove onDestory in RxFragment and onNext called in onDetach.