Rxjava解除订阅③:RxLife

Rxjava解除订阅三部曲:

前言

使用

官方介绍RxLife很厉害:
RxLife,相较于trello/RxLifecycleuber/AutoDispose,具有如下优势:

  • 直接支持在主线程回调
  • 支持在子线程订阅观察者
  • 简单易用,学习成本低
  • 性能更优,在实现上更加简单
看着挺牛的

按照官方文档一步一步来就行,先集成maven:

dependencies {
   //rxjava2
   implementation 'com.ljx.rxlife2:rxlife-rxjava:2.0.0'
       
   //rxjava3
   implementation 'com.ljx.rxlife3:rxlife-rxjava:3.0.0'
}

注:由于Google在19年就停止了非AndroidX的库的更新,故rxlife仅支持AndroidX项目,请尽快将项目迁移至AndroidX

1.Activity/Fragment:

Activity/Fragment销毁时,自动关闭RxJava管道:

Observable.timer(5, TimeUnit.SECONDS)
    .as(RxLife.as(this))     //此时的this Activity/Fragment对象
    .subscribe(aLong -> {
        Log.e("LJX", "accept =" + aLong);
    });
2.View

View被移除时,自动关闭RxJava管道

Observable.timer(5, TimeUnit.SECONDS)
    .as(RxLife.as(this))  //此时的this 为View对象
    .subscribe(aLong -> {
        Log.e("LJX", "accept =" + aLong);
    });
3.ViewModel

Activity/Fragment销毁时,自动关闭RxJava管道,ViewModel需要继承ScopeViewModel类,如下

public class MyViewModel extends ScopeViewModel {

    public MyViewModel(@NonNull Application application) {
        super(application);
    }
   
    public void test(){
        Observable.interval(1, 1, TimeUnit.SECONDS)
            .as(RxLife.asOnMain(this))  //继承ScopeViewModel后,就可以直接传this
            .subscribe(aLong -> {
                Log.e("LJX", "MyViewModel aLong=" + aLong);
            });
    }
}

注意:一定要在Activity/Fragment通过以下方式获取ViewModel对象,否则RxLife接收不到生命周期的回调

MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
4.任意类

Activity/Fragment销毁时,自动关闭RxJava管道,任意类需要继承BaseScope类,如P层:

public class Presenter extends BaseScope {

    public Presenter(LifecycleOwner owner) {
        super(owner); //添加生命周期监听
    }

    public void test(){
        Observable.interval(1, 1, TimeUnit.SECONDS)
            .as(RxLife.as(this)) //继承BaseScope后,就可以直接传this
            .subscribe(aLong -> {
                Log.e("LJX", "accept aLong=" + aLong);
            });
    }
}
5.kotlin用户

由于as是kotlin中的一个关键字,所以在kotlin中,我们并不能直接使用as(RxLife.as(this)),可以如下编写

Observable.intervalRange(1, 100, 0, 200, TimeUnit.MILLISECONDS)
    .`as`(RxLife.`as`(this))
    .subscribe { aLong ->
        Log.e("LJX", "accept=" + aLong)
    }

当然,相信没多少人会喜欢这种写法,故,RxLife针对kotlin用户,新增更为便捷的写法,如下:

Observable.intervalRange(1, 100, 0, 200, TimeUnit.MILLISECONDS)
    .life(this)
    .subscribe { aLong ->
        Log.e("LJX", "accept=" + aLong)
    }

使用life 操作符替代as操作符即可,其它均一样

6.小彩蛋 asOnMain操作符

RxLife还提供了asOnMain操作符,它可以指定下游的观察者在主线程中回调,如下:

Observable.timer(5, TimeUnit.SECONDS)
    .as(RxLife.asOnMain(this))
    .subscribe(aLong -> {
        //在主线程回调
       Log.e("LJX", "accept =" + aLong);
    });

        //等价于
Observable.timer(5, TimeUnit.SECONDS)
    .observeOn(AndroidSchedulers.mainThread())
    .as(RxLife.as(this))
    .subscribe(aLong -> {
        //在主线程回调
        Log.e("LJX", "accept =" + aLong);
    });

kotlin 用户使用lifeOnMain替代asOnMain操作符,其它均一样。
注意: RxLife类里面as操作符,皆适用于Flowable、ParallelFlowable、Observable、Single、Maybe、Completable这6个被观察者对象

7.混淆

RxLife作为开源库,可混淆,也可不混淆,如果不希望被混淆,请在proguard-rules.pro文件添加以下代码:

-keep class com.rxjava.rxlife.**{*;}

以上这些全部是官方文档,我只是搬运过来。从上述看来,RxLife是基于google的jetpack开发的,仅支持androidx及以上版本,不向下兼容。对于现有的商业应用来说,随意升级target是很危险的事情,从而也限制了RxLife的使用场景。

源码解析

  • 1.Activity/Fragment
public static <T> RxConverter<T> as(LifecycleOwner owner) {
        return as(owner, Event.ON_DESTROY, false);
    }

    public static <T> RxConverter<T> as(LifecycleOwner owner, Event event) {
        return as(owner, event, false);
    }

    public static <T> RxConverter<T> asOnMain(LifecycleOwner owner) {
        return as(owner, Event.ON_DESTROY, true);
    }
    //上面三个方法 最终调用的此方法
    private static <T> RxConverter<T> as(LifecycleOwner owner, Event event, boolean onMain) {
        return as(LifecycleScope.from(owner, event), onMain);
    }

同AutoDispose一样基于LifecycleOwner实现生命周期监控。
跟RxLifeCycle和AutoDispose一样,RxLife可以自动识别生命周期,也可以指定生命周期解绑。但跟他们不同的是,所谓自动解绑,是指定在Event.ON_DESTROY的生命周期解除绑定,可以说是没有RxLifeCycle和AutoDispose那么智能。
asasMain的区别只是最后一个参数不同,不难猜测,底层肯定是主动切到了主线程。
继续追踪as方法可以看到这个核心方法:

private void subscribeActual(Observer<? super T> observer) {
        Observable<T> upStream = this.upStream;
        if (onMain) {
            upStream = upStream.observeOn(AndroidSchedulers.mainThread());
        }
        upStream.onTerminateDetach().subscribe(new LifeObserver<>(observer, scope));
    }

果然是调用了 upStream.observeOn(AndroidSchedulers.mainThread());切了线程。

那么解绑绑定的核心方法就是LifecycleScope.from(owner, event),继续追踪下去:

static LifecycleScope from(LifecycleOwner owner, Event event) {
        return new LifecycleScope(owner.getLifecycle(), event);
    }

LifecycleScope实现了LifecycleEventObserver接口,重写了onStateChanged方法:

@Override
    public void onStateChanged(@NotNull LifecycleOwner source, Event event) {
        if (event.equals(this.event)) {
            disposable.dispose();
            source.getLifecycle().removeObserver(this);
        }
    }

此为核心代码,很简单的机制,当生命周期改变时会回调这个方法,并与设置的生命周期事件判断,如果一致则dispose,并将此监听移除。

有removeObserver那肯定也有addObserver,LifecycleScope还实现了自己写的Scope

@Override
    public void onScopeStart(Disposable d) {
        this.disposable = d;
        onScopeEnd();
        final Lifecycle lifecycle = this.lifecycle;
        if (lifecycle == null)
            throw new NullPointerException("lifecycle is null");
        lifecycle.addObserver(this);
    }

    @Override
    public void onScopeEnd() {
        final Lifecycle lifecycle = this.lifecycle;
        if (lifecycle == null)
            throw new NullPointerException("lifecycle is null");
        lifecycle.removeObserver(this);
    }

向上追踪发现AbstractLifecycleaddObserverOnMain调用onScopeStart方法,并且addObserver调用addObserverOnMain

    /**
     * 事件订阅时调用此方法
     */
    protected final void addObserver() throws Exception {
        //Lifecycle添加监听器需要在主线程执行
        if (isMainThread() || !(scope instanceof LifecycleScope)) {
            addObserverOnMain();
        } else {
            final Object object = mObject;
            AndroidSchedulers.mainThread().scheduleDirect(() -> {
                addObserverOnMain();
               ...
            });
          ...
        }
    }

还是看不出来啥时候add的,继续向上追踪,发现在LifeObserveronSubscribe调用了此方法:

final class LifeObserver<T> extends AbstractLifecycle<Disposable> implements Observer<T> {
    @Override
    public void onSubscribe(Disposable d) {
        if (DisposableHelper.setOnce(this, d)) {
            try {
                addObserver();
                downstream.onSubscribe(d);
            } catch (Throwable ex) {
                Exceptions.throwIfFatal(ex);
                d.dispose();
                onError(ex);
            }
        }
    }

细心的朋友们可能已经察觉到了,LifeObserver就是刚刚我们追踪as方法时出现过:

    private void subscribeActual(Observer<? super T> observer) {
        Observable<T> upStream = this.upStream;
        if (onMain) {
            upStream = upStream.observeOn(AndroidSchedulers.mainThread());
        }
        upStream.onTerminateDetach().subscribe(new LifeObserver<>(observer, scope));
    }

至此全部逻辑就连在了一起。

  • 2.View

自定义View的自动解绑的原理跟Activity和Fragment基本一致,唯一不同的是解绑时机。
ViewScope实现的OnAttachStateChangeListener接口,在onViewDetachedFromWindow方法中实现解除绑定。

@Override
    public void onViewDetachedFromWindow(View v) {
        disposable.dispose();
        v.removeOnAttachStateChangeListener(this);
    }

注册监听的地方跟Activity和Fragment一样,也是在onScopeStart。

  • 3.任意页面

按照官方文档描述,只要继承BaseScope就可以实现自动解绑,但实际操作中并不是所谓的只要继承就行。

public class BaseScope implements Scope, LifecycleEventObserver {

    public BaseScope(LifecycleOwner owner) {
        owner.getLifecycle().addObserver(this);
    }
}

事实上构造器得传递LifecycleOwner,那为什么官方文档上要说任意类呢,原因就像之前提到的RxLife是基于Google的jetpack来实现的,对应jetpack来说,ViewModel,LifeCycle等都有自己的生命周期,而且也都与LifecycleOwner有关,在这几个控件里自定义的组件,的确可以说是任意类。

结语

RxLife相比RxLifeCycle和AutoDispose来说,有着他自己的优势:轻量级,易用,易读,基于jetpack。缺点也很明显,只支持Androidx及以上版本,不向下兼容。项目迁移到Android X涉及到方方面面的改动,风险很大,对于这些应用来说,只能选择使用RxLifeCycle或者AutoDispose了。但google早以停掉了对Androidx以下的支持,迁移到Androidx也只是时间的问题,到时就是RxLife大放光彩的时候了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,646评论 4 366
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,979评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,391评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,356评论 0 215
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,740评论 3 293
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,836评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,022评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,764评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,487评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,728评论 2 252
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,200评论 1 263
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,548评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,217评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,134评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,921评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,919评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,766评论 2 274