RxLifecycle解决RXjava内存显露

我们来看bindToLifecycle()方法:

public abstract class RxAppCompatActivity extends AppCompatActivity implements LifecycleProvider<ActivityEvent> {

    private final BehaviorSubject<ActivityEvent> lifecycleSubject = BehaviorSubject.create();

    public final <T> LifecycleTransformer<T> bindToLifecycle() {
        //执行了这行代码,返回了LifecycleTransformer
        return RxLifecycleAndroid.bindActivity(lifecycleSubject);
    }
}

不难猜测,实际上,那个神秘人,就是我们RxAppCompatActivity 中的BehaviorSubject成员变量(它本身就是一个Observable)!

我们点进去看看:

    //1.执行了 bind(lifecycle, ACTIVITY_LIFECYCLE);
    public static <T> LifecycleTransformer<T> bindActivity(@NonNull final Observable<ActivityEvent> lifecycle) {
        return bind(lifecycle, ACTIVITY_LIFECYCLE);
    }

    //2.执行了bind(takeUntilCorrespondingEvent(lifecycle.share(), correspondingEvents))
    public static <T, R> LifecycleTransformer<T> bind(@Nonnull Observable<R> lifecycle,
                                                      @Nonnull final Function<R, R> correspondingEvents) {
        return bind(takeUntilCorrespondingEvent(lifecycle.share(), correspondingEvents));
    }

    //3.最终抵达这里,这个方法执行了什么呢?
    private static <R> Observable<Boolean> takeUntilCorrespondingEvent(final Observable<R> lifecycle,
                                                                       final Function<R, R> correspondingEvents) {
        return Observable.combineLatest(
            lifecycle.take(1).map(correspondingEvents),
            lifecycle.skip(1),
            new BiFunction<R, R, Boolean>() {
                @Override
                public Boolean apply(R bindUntilEvent, R lifecycleEvent) throws Exception {
                    return lifecycleEvent.equals(bindUntilEvent);
                }
            })
            .onErrorReturn(Functions.RESUME_FUNCTION)
            .filter(Functions.SHOULD_COMPLETE);
    }

最后我们走到了3,我们一行一行分析:

Observable.combineLatest

这行代码实际上是将lifecycle(就是我们传进来的BehaviorSubject)的事件进行了一次分割:

lifecycle.take(1)指的是最近发射的事件,比如说我们在onCreate()中执行了bindToLifecycle,那么lifecycle.take(1)指的就是ActivityEvent.CREATE,经过map(correspondingEvents),这个map中传的函数就是 1中的ACTIVITY_LIFECYCLE:

private static final Function<ActivityEvent, ActivityEvent> ACTIVITY_LIFECYCLE =
        new Function<ActivityEvent, ActivityEvent>() {
            @Override
            public ActivityEvent apply(ActivityEvent lastEvent) throws Exception {
                switch (lastEvent) {
                    case CREATE:
                        return ActivityEvent.DESTROY;
                    case START:
                        return ActivityEvent.STOP;
                    case RESUME:
                        return ActivityEvent.PAUSE;
                    case PAUSE:
                        return ActivityEvent.STOP;
                    case STOP:
                        return ActivityEvent.DESTROY;
                    case DESTROY:
                        throw new OutsideLifecycleException("Cannot bind to Activity lifecycle when outside of it.");
                    default:
                        throw new UnsupportedOperationException("Binding to " + lastEvent + " not yet implemented");
                }
            }
        };

也就是说,lifecycle.take(1).map(correspondingEvents)实际上是返回了 CREATE 对应的事件 DESTROY ,它意味着本次订阅将在Activity的onDestory进行取消。

lifecycle.skip(1)就简单了,除去第一个保留剩下的,以ActivityEvent.Create为例,这里就剩下:

ActivityEvent.START
ActivityEvent.RESUME
ActivityEvent.PAUSE
ActivityEvent.STOP
ActivityEvent.DESTROY

第三个参数 意味着,lifecycle.take(1).map(correspondingEvents)的序列和 lifecycle.skip(1)进行combine,形成一个新的序列:

false,false,fasle,false,true

这意味着,当Activity走到onStart生命周期时,为false,这次订阅不会取消,直到onDestroy,为true,订阅取消。

而后的onErrorReturn和filter是对异常的处理和判断是否应该结束订阅:

    //异常处理
    static final Function<Throwable, Boolean> RESUME_FUNCTION = new Function<Throwable, Boolean>() {
        @Override
        public Boolean apply(Throwable throwable) throws Exception {
            if (throwable instanceof OutsideLifecycleException) {
                return true;
            }
            Exceptions.propagate(throwable);
            return false;
        }
    };
    //是否应该取消订阅,可以看到,这依赖于上游的boolean
    static final Predicate<Boolean> SHOULD_COMPLETE = new Predicate<Boolean>() {
        @Override
        public boolean test(Boolean shouldComplete) throws Exception {
            return shouldComplete;
        }
    };

bind生成LifecycleTransformer

看懂了3,我们回到2,我们生成了一个Observable,然后通过bind(Observable)方法,生成LifecycleTransformer并返回:

    public static <T, R> LifecycleTransformer<T> bind(@Nonnull final Observable<R> lifecycle) {
        return new LifecycleTransformer<>(lifecycle);
    }

神秘人的神秘面纱就此揭开。

总结

RxLifecycle并不难以理解,相反,它的设计思路很简单:

1.在Activity中,定义一个Observable(Subject),在不同的生命周期发射不同的事件;
2.通过compose操作符(内部实际上还是依赖takeUntil操作符),定义了上游数据,当其接收到Subject的特定事件时,取消订阅;
3.Subject的特定事件并非是ActivityEvent,而是简单的boolean,它已经内部通过combineLast操作符进行了对应的转化。

实际上,Subject和ActivityEvent对RxLifecycle的使用者来讲,是对应隐藏的。我们只需要调用它提供给我们的API,而内部的实现者我们无需考虑,但是也只有去阅读和理解了它的思想,我们才能更好的选择使用这个库。

转折:AutoDispose

在我沉迷于RxLifecycle对项目的便利时,一个机会,我有幸阅读到了 Daniel Lew 的文章《Why Not RxLifecycle?》(为什么放弃使用RxLifecycle)

作为RxLifecycle的作者,Daniel Lew客观陈述了使用RxLifecycle在开发时所遇到的窘境。并且为我们提供了一个他认为更优秀的设计:

AutoDispose: Automatic binding+disposal of RxJava 2 streams.

我花了一些时间研究了一下AutoDispose,不得不承认,AutoDispose相比较RxLifecycle,前者更加健壮,并且拥有更优秀的拓展性,如果我的项目需要一个处理RxJava自动取消订阅的库,也许AutoDispose更为适合。

更让我感到惊喜的是,AutoDispose的设计思想,有很大一部分和RxLifecycle相似,而且我在其文档上,看到了Uber的工程师对于Daniel Lew 所维护的 RxLifecycle 感谢,也感谢Daniel Lew 对于 AutoDispose的很大贡献:

以下摘录于AutoDispose的官方文档:

Special thanks go to Dan Lew (creator of RxLifecycle), who helped pioneer this area for RxJava in android and humored many of the discussions around lifecycle handling over the past couple years that we've learned from. Much of the internal scope resolution mechanics of
AutoDispose are inspired by RxLifecycle.

在我尝试将AutoDispose应用在项目中时,我发现国内对于这个库所应用的不多,我更希望有更多朋友能够和我一起使用这个库,于是我准备写一篇关于AutoDispose使用方式的文章。

但在这之前,我还是希望能够先将RxLifecycle的个人心得分享给大家,原因有二:

一是RxLifecycle更简单,原理也更好理解,学习一个库不仅仅是为了会使用它,我们更希望能够从源码中学习到作者优秀的设计和思想。因此,如果是从未接触过这两个库的开发者,直接入手AutoDispose,在我看来不如先入手RxLifecycle

二是AutoDispose的很大一部分设计核心源于RxLifecycle,理解了RxLifecycle,更有利于AutoDispose的学习。

作者:却把清梅嗅
链接:https://www.jianshu.com/p/8311410de676
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

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

推荐阅读更多精彩内容