一个简单非侵入式的AutoDispose

2,270 阅读1分钟

0x00 前言

RxJava 现在在各个项目中应用非常广泛,但使用不当很容易出现内存泄漏的风险。如今市面也有很多类似可以避免内存泄漏的RxJava相关库。例如Uber开源的AutoDispose
本文的实现也参考了 AutoDispose的用法,是非侵入式的实现方式。当然还有一些侵入式的实现,不过我认为非侵入式会更好一些。

直接上代码

核心原理是使用Android Lifecycle接口来实现监听当前页面的显示和销毁的状态,非常简单。

public class AutoDisposable<T> implements ObservableConverter<T, Observable<T>> {

    private static final String TAG = "AutoDisposable";

    private LifecycleOwner mLifecycleOwner;
    private CompositeDisposable mDisposable = new CompositeDisposable();

    public AutoDisposable(@androidx.annotation.NonNull LifecycleOwner owner) {
        mLifecycleOwner = owner;
        initLifecycle();
    }

    public AutoDisposable(@androidx.annotation.NonNull View view) {
        mLifecycleOwner = new ViewLifecycleOwner(view);
        initLifecycle();
    }

    private void initLifecycle() {
        mLifecycleOwner.getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@androidx.annotation.NonNull LifecycleOwner source, @androidx.annotation.NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    Log.d(TAG, "do ON_DESTROY");
                    mLifecycleOwner.getLifecycle().removeObserver(this);
                    mLifecycleOwner = null;
                    if (mDisposable != null) {
                        mDisposable.dispose();
                    }
                }
            }
        });
    }

    @Override
    public Observable<T> apply(@NonNull Observable<T> upstream) {
        return upstream.filter(this::canCallback).doOnSubscribe(disposable -> {
            if (mDisposable != null) {
                mDisposable.add(disposable);
                Log.d(TAG, "doOnSubscribe:" + mDisposable.size());
            }
        });
    }

    private boolean canCallback(T t) {
        if (mLifecycleOwner == null || mDisposable == null) {
            Log.d(TAG, "canCallback >> lifecycleOwner or disposable is null");
            return false;
        }
        if (mDisposable.isDisposed()) {
            Log.d(TAG, "canCallback >> isDisposed");
            return false;
        }
        if (mLifecycleOwner.getLifecycle().getCurrentState() == Lifecycle.State.DESTROYED) {
            Log.d(TAG, "canCallback >> DESTROYED");
            return false;
        }
        return true;
    }

    private static class ViewLifecycleOwner implements LifecycleOwner {
        private LifecycleRegistry lifecycleRegistry;

        private ViewLifecycleOwner(View view) {
            lifecycleRegistry = new LifecycleRegistry(this);
            view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
                @Override
                public void onViewAttachedToWindow(View v) {
                    lifecycleRegistry.setCurrentState(Lifecycle.State.CREATED);
                }

                @Override
                public void onViewDetachedFromWindow(View v) {
                    lifecycleRegistry.setCurrentState(Lifecycle.State.DESTROYED);
                    view.removeOnAttachStateChangeListener(this);
                }
            });
        }

        @androidx.annotation.NonNull
        @Override
        public Lifecycle getLifecycle() {
            return lifecycleRegistry;
        }
    }

}

0x01 简单用法

rxjava中使用as或者to可以将一个Observable对象转化为另外一个Observable对象,我们使用这两个操作符,就可以很方便的实现rxjava与生命周期函数进行绑定,从而避免内存泄漏的风险。

1、与View进行绑定

Observable.interval(10, TimeUnit.MILLISECONDS).as(new AutoDisposable<>(textView)).subscribe(aLong -> {
            	Log.d("RXJava", "aLong:" + aLong);
            });

2、或者在ActivityFragment中,则会与LifeCycle进行绑定

Observable.interval(10, TimeUnit.MILLISECONDS).as(new AutoDisposable<>(this)).subscribe(aLong -> {
            	Log.d("RXJava", "aLong:" + aLong);
            });