问:RxJava:clear (CompositeDisposable) 方法在内部如何工作

Q : RxJava : How the clear (CompositeDisposable) method work internally

匿名 class 持有对封闭 class 的引用。

在下面的例子中,我创建了一个小的Activity。在 onCreate 方法中,我只是在另一个 Thread 上添加一个计时器,添加一个 CompositeDisposable 并在 onDestroy 中清除它。

显然没有 CompositeDisposable,它会造成内存泄漏。使用 CompositeDisposable 它不会造成任何内存泄漏,但它是如何工作的呢?

RxJava 只是中断线程并在每个回调上设置 null 吗?你能提供一些在 RxJava 源代码中完成这项工作的行吗,我想它在 dispose 方法附近。

public class MainActivity extends AppCompatActivity {

private String TAG = "MainActivity";

private CompositeDisposable composite = new CompositeDisposable();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    composite.add(Flowable
            .just(1)
            .timer(90, TimeUnit.SECONDS)
            .subscribeOn(Schedulers.io())
            .subscribeWith(new DisposableSubscriber<Long>() {

                @Override
                public void onNext(Long aLong) { sayHello(); }

                @Override
                public void onError(Throwable t) { sayHello(); }

                @Override
                public void onComplete() { sayHello(); }
            }));
}

@Override
protected void onDestroy() {
    super.onDestroy();

    composite.clear();
}

public void sayHello () { Log.w(TAG, "Hello everyone"); }

正是在dispose方法的源码中。您也可以在 IDE 中跳转到库中方法的源代码,在 IntelliJ 中它是 Ctrl+B on Windows 或 ⌘B 在 Mac 上,在 Eclipse 中是 F3.

无论如何,这是 dispose 方法的来源(评论我的):

@Override
public void dispose() {
    if (disposed) { // nothing to do
        return;
    }
    OpenHashSet<Disposable> set; // this is the same type as our field that holds the Disposables
    synchronized (this) {
        if (disposed) { 
            return; // another thread did it while we got our lock, so nothing to do
        }
        disposed = true; // setting this flag is safe now, we're the only ones disposing
        set = resources; // the references are now in this local variable
        resources = null; // our field no longer has the references
    }

    dispose(set); // from here on out, only this method has the references to the Disposables
}

然后是我们在最后一行调用的 dispose(OpenHashSet<Disposable>) 方法的完整代码(主要是错误处理,我认为这是不言自明的):

/**
 * Dispose the contents of the OpenHashSet by suppressing non-fatal
 * Throwables till the end.
 * @param set the OpenHashSet to dispose elements of
 */
void dispose(OpenHashSet<Disposable> set) {
    if (set == null) {
        return;
    }
    List<Throwable> errors = null;
    Object[] array = set.keys();
    for (Object o : array) {
        if (o instanceof Disposable) {
            try {
                ((Disposable) o).dispose();
            } catch (Throwable ex) {
                Exceptions.throwIfFatal(ex);
                if (errors == null) {
                    errors = new ArrayList<Throwable>();
                }
                errors.add(ex);
            }
        }
    }
    if (errors != null) {
        if (errors.size() == 1) {
            throw ExceptionHelper.wrapOrThrow(errors.get(0));
        }
        throw new CompositeException(errors);
    }
}

如您所见,在该方法的最后,set 现在可以被垃圾回收,因为没有人持有对它的引用。