这个系列的前几篇文章是传统rxjava的数据流传递模式,我们知道,observable的链式调用,是下游被观察者持有上有被观察者的过程,发起订阅的时候是上游观察者持有下游观察者的过程。到最先的被观察者,通过本层级实现的消息队列或者发射器开始发射数据流,而上游的观察者或消息队列持有下游的观察者,通过观察者的接Observer实现最终回调。以上是对以上几篇文章的总结,不明白的朋友可以详细看一下这个系列的前几篇文章。既然明白了rxjava的数据流传递机制,试想一下,假如因为某些原因,我不想等待回调的结果了,为了节省内存,我要把发射关掉(比如在activity或fragment下面,用rxjava做耗时操作,而我想隐藏或关闭该界面,为了避免内存泄漏,必须终止rxjava的传递过程,该怎么办呢?),这也是本篇文章主要探讨Disposable,为什么这个东东可以终止呢,还是从源码开始吧,这才符合本博客的主题嘛!
首先,我们先看一下直观的现象,就用以下代码为例。
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
emitter.onNext("hello");
emitter.onNext("world");
emitter.onComplete();
}
}).subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
Disposable disposable;
@Override
public void onSubscribe(Disposable d) {
disposable=d;
}
@Override
public void onNext(String s) {
disposable.dispose();
Log.i("test",s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
看一下运行运行结果
可以看到,只要disposable调用dispose方法,这个发射机制就终结了。
现象已经看到了,我们通过源代码解析上面的现象。
先贴一张对象关系图,
这个关系图,是根据代码调用关系画出来的。 当我们在测试代码里面调用disposable.dispose()的时候,这个disposable是ObserveOnObserver的实例,所以它的方法如下
@Override
public void dispose() {
if (!disposed) {//只要你的代码没有问题,不发生异常,初始值为false
disposed = true;//已经被处理过
upstream.dispose();//关闭上游的数据源
worker.dispose();//关闭worker
if (getAndIncrement() == 0) {
queue.clear();//队列清空
}
}
}
一般情况下,disposed为false,然后往下执行。upstream是SubscribeOnObserver它的实例,那么这个类实现了Disposable接口,那它又做了什么呢?请看代码
@Override
public void dispose() {
DisposableHelper.dispose(upstream);
DisposableHelper.dispose(this);
}
这个DisposableHelper.dispose方法做了什么操作
/**
* Atomically disposes the Disposable in the field if not already disposed.
* @param field the target field
* @return true if the current thread managed to dispose the Disposable
*/
public static boolean dispose(AtomicReference field) {
Disposable current = field.get();
Disposable d = DISPOSED;
if (current != d) {
current = field.getAndSet(d);//把当前field的Disposable取出来,并设置为已经处理过,
if (current != d) {
if (current != null) {
current.dispose();//处理掉dispose
}
return true;
}
}
return false;
}
该方法就是AtomicReference里面的value取出来,判断一下是否处理了,如果没处理过,处理掉。处理了,返回false
我们再回到代码片段3,这里的upstream是CreateEmitter的实例,它存储的Disposable为null,根据代码片段四,给upstream设置Disposable为DISPOSED,设置这样,CreateEmitter就可以停止发射了嘛,看看一下方法就明白了
@Override
public boolean isDisposed() {
return DisposableHelper.isDisposed(get());
}
/**
* Checks if the given Disposable is the common {@link #DISPOSED} enum value.
* @param d the disposable to check
* @return true if d is {@link #DISPOSED}
*/
public static boolean isDisposed(Disposable d) {
return d == DISPOSED;
}
根据以上方法,可以知道CreateEmitter的isDisposed()返回true,这会对发射数据产生影响嘛,答案是肯定的,看一下代码
@Override
public void onNext(T t) {
if (t == null) {
onError(new NullPointerException("onNext called with null. Null values are generally not allowed in 2.x operators and sources."));
return;
}
if (!isDisposed()) {
observer.onNext(t);
}
}
CreateEmitter的isDisposed()返回true,所以不会往下游发射数据。
那代码片段3的DisposableHelper.dispose(this);这个代码做了什么事呢?这个this还记得吧,是SubscribeOnObserver的实例。
DisposableHelper.dispose(this)方法里面的参数是atomicReference里面设置了一个Disposable,什么时候设置的呢?经过查找源码可以看到,是在ObservableSubscribeOn.subscribeActual方法里面设置的,这个value是什么呢?看下源码
@Override
public void subscribeActual(final Observer super T> observer) {
final SubscribeOnObserver parent = new SubscribeOnObserver(observer);
observer.onSubscribe(parent);
//该行代码设置的disposable,scheduler.scheduleDirect方法创建了disposable
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
那我们点击进去看看,
/**
* Schedules the execution of the given task with the given time delay.
*
*
* This method is safe to be called from multiple threads but there are no
* ordering guarantees between tasks.
*
* @param run the task to schedule
* @param delay the delay amount, non-positive values indicate non-delayed scheduling
* @param unit the unit of measure of the delay amount
* @return the Disposable that let's one cancel this particular delayed task.
* @since 2.0
*/
@NonNull
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
final Worker w = createWorker();
final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
//这个是个disposable,w是它的属性,NewThreadWorker
DisposeTask task = new DisposeTask(decoratedRun, w);
//w这里面包装的是线程池
w.schedule(task, delay, unit);
return task;
}
DisposeTask也就是AtomicReference的value,那根据代码片段4会执行DisposeTask的dispose()方法,它是怎么调用的呢?
@Override
public void dispose() {
runner是不是当前线程,而且w是不是newThreadWorker
if (runner == Thread.currentThread() && w instanceof NewThreadWorker) {
((NewThreadWorker)w).shutdown();关闭
} else {
w.dispose();
}
}
根据运行环境两者都可能发生,那么newThreadWorker这两个方法的实现是什么呢?
@Override
public void dispose() {
if (!disposed) {
disposed = true;
executor.shutdownNow();
}
}
/**
* Shuts down the underlying executor in a non-interrupting fashion.
*/
public void shutdown() {
if (!disposed) {
disposed = true;
executor.shutdown();
}
}
关闭线程池,厉害了。如果还没有发生线程转换订阅,执行以上的操作 ,不会把任务添加到线程池,如果已经进行任务订阅,把上游的回调关闭,不会往下游发射事件。ok,代码片段3分析完毕,让我们再回到代码片段二的worker.dispose()这个代码
而这个worker是HandlerWorker的实例,而dispose的实现是什么呢?
@Override
public void dispose() {
disposed = true;
//去除消息,不会发生线程转换的最终回调
handler.removeCallbacksAndMessages(this /* token */);
}
当然了,还有其他地方也进行了限制,在这里不做详细叙述,代码片段2的最后一段话就是清空队列,整个数据流的传递过程就终止了。也符合Observer的接口定义里面注释的那样
/**
* Provides the Observer with the means of cancelling (disposing) the
* connection (channel) with the Observable in both
* synchronous (from within {@link #onNext(Object)}) and asynchronous manner.
* @param d the Disposable instance whose {@link Disposable#dispose()} can
* be called anytime to cancel the connection
* @since 2.0
*/
void onSubscribe(@NonNull Disposable d);
dispose方法可以在任何时候撤销连接,也就是rxjava的数据流的传递过程。