RxJava中CompositeDisposable注意事项

在RxJava中,Observable被订阅后,可以得到一个Disposable对象。为了防止内存泄露,一般情况下,都会在Activity结束的时候调用Disposable对象的dispose()方法,解除订阅。

RxJava2中,提供了一个CompositeDisposable类作为Disposable的容器。

1
2
3
4
5
6
7
8
9
10
11
12
13
public final class CompositeDisposable implements Disposable, DisposableContainer {

OpenHashSet<Disposable> resources;

volatile boolean disposed;

/**
* Creates an empty CompositeDisposable.
*/
public CompositeDisposable() {
}
...
}

可以看出,CompositeDisposable实现了Disposable接口(void dispose();方法);实现了DisposableContainer接口,可以add、remove、delete操作Disposable。

重点要关注两个方法:

1、add(@NonNull Disposable d)这个方法是将一个dispoable加入CompositeDisposable中,当Activity或者Fragment的生命周期结束的时候,通过

dispose()方法将Observable的订阅事件取消关联,防止内存泄露。

2、public void dispose()这个方法就是CompositeDisposable中将所有的Observable的订阅事件取消关联使用。


之前遇到过一个问题:

使用MVP模式开发的时候,Activity A的Presenter中包含CompositeDisposable对象,Activity A的onStart()方法中关联了A的Presenter,当Activity A 跳转到Activity B的时候,我在A的onStop()方法中调用了CompositeDisposable.dispose()方法。当Activity B 调用finish()方法结束时候,回到Activity A页面,Activity A上的所有关于RxJava的调用都失效。

我通过Debug的方式一层层的查看方法的调用栈对比正常的情况,最终发现:

CompositeDisposable的dispose()方法在被调用之后,所有的add()进来的Disposable都会直接调用自身的dispose()方法,也就是说在事件刚被绑定监听的时候就被解除绑定了。

查看源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public void dispose() {
if (disposed) {
return;
}
OpenHashSet<Disposable> set;
synchronized (this) {
if (disposed) {
return;
}
disposed = true;
set = resources;
resources = null;
}

dispose(set);
}

在dispose() 方法调用的时候,会将全局变量disposed置为true。

再看add方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override
public boolean add(@NonNull Disposable d) {
ObjectHelper.requireNonNull(d, "d is null");
if (!disposed) {
synchronized (this) {
if (!disposed) {
OpenHashSet<Disposable> set = resources;
if (set == null) {
set = new OpenHashSet<Disposable>();
resources = set;
}
set.add(d);
return true;
}
}
}
d.dispose();
return false;
}

在add一个disposable的时候,如果全局变量disposed为true,那么不会走if条件,而是直接走下面的d.dispose();这句,直接将监听的事件解除绑定。

所有,CompositeDisposable的dispose()方法一定要放到Activity和Fragment生命周期结束的地方——onDestroy()中。