您现在的位置是:首页 > 文章详情

Android开发之深度项目设计探索(二)

日期:2018-08-06点击:518

《Android开发之深度项目设计探索(一)》 这篇文章中,主要描述了深度项目架构设计会涉及到的一些知识点,那么这篇文章主要介绍的是 RxLifecycle 使用及源码分析。

RxLifecycle :

在Android进行面试的时候,经常会被问到的就是Android的内存泄漏、泄漏场景、泄漏原因以及解决办法。如果你提到了Rxjava2,面试官可能会接连发问Rxjava2在使用过程中会有一些什么问题?这时就可以谈到Rxjava如果在一些特定场景没有及时解绑订阅可能会导致内存泄漏。

泄漏的原因是:当RxJava发布一个订阅后,此时页面执行了finish的生命周期,但订阅逻辑还未完成。如果没有及时取消订阅,就会导致Activity/Fragment无法被回收,从而引发内存泄漏。但是相应的,Rxjava系列也提供了解决办法,那就是使用RxLifecycle 。

RxLifecycle官方文档

通过官方文档了解发现,RxLifecycle库的使用和集成也是简单和快捷的

A:RxLifecycle对应的依赖(最新版本)
 // 这是RxLifecycle最主要的依赖 implementation 'com.trello.rxlifecycle2:rxlifecycle:2.2.2' // If you want to bind to Android-specific lifecycles //如果你想绑定Android的生命周期 implementation 'com.trello.rxlifecycle2:rxlifecycle-android:2.2.2' // If you want pre-written Activities and Fragments you can subclass as providers //如果想在预先写好的Activities and Fragments,你可以作为其父类的子类 implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.2' // If you want pre-written support preference Fragments you can subclass as providers //如果想在预先支持的 Fragments,你可以作为其父类的子类 implementation 'com.trello.rxlifecycle2:rxlifecycle-components-preference:2.2.2' // If you want to use Navi for providers // Android使用的库,继承NaviActivity使用 implementation 'com.trello.rxlifecycle2:rxlifecycle-navi:2.2.2' // If you want to use Android Lifecycle for providers //如果你想为其提供Android生命周期 implementation 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle:2.2.2' // If you want to use Kotlin syntax //如果你想使用Kotlin语法 implementation 'com.trello.rxlifecycle2:rxlifecycle-kotlin:2.2.2' // If you want to use Kotlin syntax with Android Lifecycle //如果你想使用Kotlin语法作用在Android生命周期上 implementation 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle-kotlin:2.2.2' 

下面是一些基本的使用和说明:

首先是 绑定生命周期:

 myObservable.compose(RxLifecycle.bind(lifecycle)).subscribe(); 

接着是 绑定特殊的生命周期(onStart onStop等等):

myObservable.compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) .subscribe(); 

然后是 通过RxLifecycle在适当的时间来结束:

myObservable.compose(RxLifecycleAndroid.bindActivity(lifecycle)).subscribe(); 

通过文档我们可以知道:如果在onStart( )这个生命周期里面绑定,它就会在onStop()这个终止绑定;如果我们在onPause( )之后订阅, 那么它就会在其下一个生命周期终止绑定,(在onPause( )之后订阅,因为onStop()是其下一个生命周期,如果Activity执行到了这里,就会解绑)

下面上一段代码加深RxLifecycle的理解和使用:

public class LifeActivity extends RxAppCompatActivity{ @Override protected void onStart() { super.onStart(); Observable.interval(2, TimeUnit.SECONDS) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .compose(this.bindToLifecycle()) .subscribe(); } } 

理论上我们需要使用compose操作符,然后加上bindToLifecycle即可完成简单的使用(注意:这里的 LifeActivity继承的是RxAppCompatActivity)看到了这里,可能疑惑的是,RxLifecycle具体的绑定该如何理解?里面的生命周期又是如何操作的?

是这样,这里的生命周期是由 LifecycleProvider<T> 来提供的,实现的方式有以下四种:
1:继承父类,RxActivity, RxFragment
2:使用 Navi 以及 Rxlifecycle-navi
3:使用 Android's lifecycle
4:自己编写实现

首先看第一种:也就是上面的代码,直接继承RxAppCompatActivity,然后点开RxAppCompatActivity源码会发现很多事情,这个后面说。

第二种:继承NaviActivity(需要导入上面提供的Navi对应的依赖)下面是参考代码

public class NaviLifeActivity extends NaviActivity{ private final LifecycleProvider<ActivityEvent> provider = NaviLifecycle.createActivityLifecycleProvider(this); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initLifecycle(); } private void initLifecycle(){ Observable.interval(2, TimeUnit.SECONDS) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .compose(provider.bindToLifecycle()) .subscribe(); } } 

第三种和第四种由于涉及到另外的内容这里就不描述了。

值得一提的是:compose方法需在subscribeOn方法之后使用。

RxLifecycle源码分析:

说到源码,我们首先进入RxAppCompatActivity看看,因为compose(this.bindToLifecycle()) 这句API里面的this,代表的就是当前继承了RxAppCompatActivity的子类,奔着研究分析的精神,下面是
RxAppCompatActivity 的源码:

public abstract class RxAppCompatActivity extends AppCompatActivity implements LifecycleProvider<ActivityEvent> { private final BehaviorSubject<ActivityEvent> lifecycleSubject = BehaviorSubject.create(); @Override @NonNull @CheckResult public final Observable<ActivityEvent> lifecycle() { return lifecycleSubject.hide(); } @Override @NonNull @CheckResult public final <T> LifecycleTransformer<T> bindUntilEvent(@NonNull ActivityEvent event) { return RxLifecycle.bindUntilEvent(lifecycleSubject, event); } @Override @NonNull @CheckResult public final <T> LifecycleTransformer<T> bindToLifecycle() { return RxLifecycleAndroid.bindActivity(lifecycleSubject); } @Override @CallSuper protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); lifecycleSubject.onNext(ActivityEvent.CREATE); } @Override @CallSuper protected void onStart() { super.onStart(); lifecycleSubject.onNext(ActivityEvent.START); } @Override @CallSuper protected void onResume() { super.onResume(); lifecycleSubject.onNext(ActivityEvent.RESUME); } @Override @CallSuper protected void onPause() { lifecycleSubject.onNext(ActivityEvent.PAUSE); super.onPause(); } @Override @CallSuper protected void onStop() { lifecycleSubject.onNext(ActivityEvent.STOP); super.onStop(); } @Override @CallSuper protected void onDestroy() { lifecycleSubject.onNext(ActivityEvent.DESTROY); super.onDestroy(); } } 

可以看到在Activity具体生命周期里面进行了对应的事件发送!

1:BehaviorSubject与ActivityEvent

RxAppCompatActivity源码中内部第一行代码是创建了一个BehaviorSubject实例对象,里面的泛型是ActivityEvent,首先看下 ActivityEvent

/** * Lifecycle events that can be emitted by Activities. */ public enum ActivityEvent { CREATE, START, RESUME, PAUSE, STOP, DESTROY } 

哦,细心的你一眼就看到了这是个枚举,里面的value对应的就是Activity生命周期的那些生命周期(因为在生命周期里面进行了发射嘛);那么,什么是BehaviorSubject?BehaviorSubject的由于源码较多这里就不贴出来了,这个类它继承了Subject<T>,那 Subject<T> 又是什么?源码如下:

public abstract class Subject<T> extends Observable<T> implements Observer<T> { /** * Returns true if the subject has any Observers. * <p>The method is thread-safe. * @return true if the subject has any Observers */ public abstract boolean hasObservers(); /** * Returns true if the subject has reached a terminal state through an error event. * <p>The method is thread-safe. * @return true if the subject has reached a terminal state through an error event * @see #getThrowable() * @see #hasComplete() */ public abstract boolean hasThrowable(); /** * Returns true if the subject has reached a terminal state through a complete event. * <p>The method is thread-safe. * @return true if the subject has reached a terminal state through a complete event * @see #hasThrowable() */ public abstract boolean hasComplete(); /** * Returns the error that caused the Subject to terminate or null if the Subject * hasn't terminated yet. * <p>The method is thread-safe. * @return the error that caused the Subject to terminate or null if the Subject * hasn't terminated yet */ @Nullable public abstract Throwable getThrowable(); /** * Wraps this Subject and serializes the calls to the onSubscribe, onNext, onError and * onComplete methods, making them thread-safe. * <p>The method is thread-safe. * @return the wrapped and serialized subject */ @NonNull public final Subject<T> toSerialized() { if (this instanceof SerializedSubject) { return this; } return new SerializedSubject<T>(this); } } 

哦,上帝,Subject继承了Observable、又实现了Observer接口,这也就说明Subject即可作为被观察者,也可以作为观察者。同理,他的子类BehaviorSubject也具备同样的功能。
下面是关于BehaviorSubject操作符的一张图:


img_8f8a946e7530478bfbf83ef83e855c1a.png
BehaviorSubject

BehaviorSubject的简单理解就是,发送离订阅最近的上一个值,没有上一个值的时候会发送默认值,接下来(如果有数据)则继续发射原始Observable的数据。

2:bindUntilEvent( ActivityEvent event) 、LifecycleTransformer、takeUntil

在RxAppCompatActivity 源码中我们看到了bindUntilEvent()这个方法,最终的的返回值类型是 LifecycleTransformer 那这个LifecycleTransformer又是什么?

public final class LifecycleTransformer<T> implements ObservableTransformer<T, T>, FlowableTransformer<T, T>, SingleTransformer<T, T>, MaybeTransformer<T, T>, CompletableTransformer { final Observable<?> observable; LifecycleTransformer(Observable<?> observable) { checkNotNull(observable, "observable == null"); this.observable = observable; } @Override public ObservableSource<T> apply(Observable<T> upstream) { return upstream.takeUntil(observable); } //...... } 

经过源码可以发现,这个LifecycleTransformer实现了大量的XXXTransformer,内部的方法大都使用了apply方法,这个方法实则是调用了takeUntil操作符,那么这个takeUntil操作符是什么意思?

img_8aef6573397eef1c46536fb0e9cb5b85.png
takeUntil

takeUntil操作符简单理解就是,当第二个Observable发射了一项数据或者终止时,丢弃原Observable发射的任何数据。注意:这里是满足条件丢弃任何发送的数据(该操作符的应用场景是不是,在onDestroy( )里面取消订阅,解决内存泄漏的隐患)

3:bindToLifecycle()

我们知道,绑定的API是bindToLifecycle()这一行代码,那么我们就抽丝剥茧,根据RxAppCompatActivity源码得知,bindToLifecycle()这行代码最终返回了 RxLifecycleAndroid.bindActivity(lifecycleSubject),源码跟进,进入到了RxLifecycleAndroid,下面是 RxLifecycleAndroid 源码:

public class RxLifecycleAndroid { private RxLifecycleAndroid() { throw new AssertionError("No instances"); } /** * Binds the given source to an Activity lifecycle. * <p> * This helper automatically determines (based on the lifecycle sequence itself) when the source * should stop emitting items. In the case that the lifecycle sequence is in the * creation phase (CREATE, START, etc) it will choose the equivalent destructive phase (DESTROY, * STOP, etc). If used in the destructive phase, the notifications will cease at the next event; * for example, if used in PAUSE, it will unsubscribe in STOP. * <p> * Due to the differences between the Activity and Fragment lifecycles, this method should only * be used for an Activity lifecycle. * * @param lifecycle the lifecycle sequence of an Activity * @return a reusable {@link LifecycleTransformer} that unsubscribes the source during the Activity lifecycle */ @NonNull @CheckResult public static <T> LifecycleTransformer<T> bindActivity(@NonNull final Observable<ActivityEvent> lifecycle) { return bind(lifecycle, ACTIVITY_LIFECYCLE); } /** * Binds the given source to a Fragment lifecycle. * <p> * This helper automatically determines (based on the lifecycle sequence itself) when the source * should stop emitting items. In the case that the lifecycle sequence is in the * creation phase (CREATE, START, etc) it will choose the equivalent destructive phase (DESTROY, * STOP, etc). If used in the destructive phase, the notifications will cease at the next event; * for example, if used in PAUSE, it will unsubscribe in STOP. * <p> * Due to the differences between the Activity and Fragment lifecycles, this method should only * be used for a Fragment lifecycle. * * @param lifecycle the lifecycle sequence of a Fragment * @return a reusable {@link LifecycleTransformer} that unsubscribes the source during the Fragment lifecycle */ @NonNull @CheckResult public static <T> LifecycleTransformer<T> bindFragment(@NonNull final Observable<FragmentEvent> lifecycle) { return bind(lifecycle, FRAGMENT_LIFECYCLE); } /** * Binds the given source to a View lifecycle. * <p> * Specifically, when the View detaches from the window, the sequence will be completed. * <p> * Warning: you should make sure to use the returned Transformer on the main thread, * since we're binding to a View (which only allows binding on the main thread). * * @param view the view to bind the source sequence to * @return a reusable {@link LifecycleTransformer} that unsubscribes the source during the View lifecycle */ @NonNull @CheckResult public static <T> LifecycleTransformer<T> bindView(@NonNull final View view) { checkNotNull(view, "view == null"); return bind(Observable.create(new ViewDetachesOnSubscribe(view))); } // Figures out which corresponding next lifecycle event in which to unsubscribe, for Activities 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"); } } }; // Figures out which corresponding next lifecycle event in which to unsubscribe, for Fragments private static final Function<FragmentEvent, FragmentEvent> FRAGMENT_LIFECYCLE = new Function<FragmentEvent, FragmentEvent>() { @Override public FragmentEvent apply(FragmentEvent lastEvent) throws Exception { switch (lastEvent) { case ATTACH: return FragmentEvent.DETACH; case CREATE: return FragmentEvent.DESTROY; case CREATE_VIEW: return FragmentEvent.DESTROY_VIEW; case START: return FragmentEvent.STOP; case RESUME: return FragmentEvent.PAUSE; case PAUSE: return FragmentEvent.STOP; case STOP: return FragmentEvent.DESTROY_VIEW; case DESTROY_VIEW: return FragmentEvent.DESTROY; case DESTROY: return FragmentEvent.DETACH; case DETACH: throw new OutsideLifecycleException("Cannot bind to Fragment lifecycle when outside of it."); default: throw new UnsupportedOperationException("Binding to " + lastEvent + " not yet implemented"); } } }; } 

嗯,首先看到bindActivity(final Observable<ActivityEvent> lifecycle)这个方法,这个方法最终返回了bind(lifecycle, ACTIVITY_LIFECYCLE);

请注意,前方高能: ACTIVITY_LIFECYCLE,这个ACTIVITY_LIFECYCLE的源码也是上面的截图,可以看到通过switch语句进行条件筛选最终返回ActivityEvent这个枚举里面的属性值(仔细观看的话源码下面还有Fragment对应的生命周期),可能你会问,为什么这是对应的生命周期?让我们首先看回bind(lifecycle, ACTIVITY_LIFECYCLE); 这个方法,点进去看,进入到了 RxLifecycle 这个类,源码如下:

public class RxLifecycle { private RxLifecycle() { throw new AssertionError("No instances"); } /** * Binds the given source to a lifecycle. * <p> * When the lifecycle event occurs, the source will cease to emit any notifications. * * @param lifecycle the lifecycle sequence * @param event the event which should conclude notifications from the source * @return a reusable {@link LifecycleTransformer} that unsubscribes the source at the specified event */ @Nonnull @CheckReturnValue public static <T, R> LifecycleTransformer<T> bindUntilEvent(@Nonnull final Observable<R> lifecycle, @Nonnull final R event) { checkNotNull(lifecycle, "lifecycle == null"); checkNotNull(event, "event == null"); return bind(takeUntilEvent(lifecycle, event)); } private static <R> Observable<R> takeUntilEvent(final Observable<R> lifecycle, final R event) { return lifecycle.filter(new Predicate<R>() { @Override public boolean test(R lifecycleEvent) throws Exception { return lifecycleEvent.equals(event); } }); } /** * Binds the given source to a lifecycle. * <p> * This helper automatically determines (based on the lifecycle sequence itself) when the source * should stop emitting items. Note that for this method, it assumes <em>any</em> event * emitted by the given lifecycle indicates that the lifecycle is over. * * @param lifecycle the lifecycle sequence * @return a reusable {@link LifecycleTransformer} that unsubscribes the source whenever the lifecycle emits */ @Nonnull @CheckReturnValue public static <T, R> LifecycleTransformer<T> bind(@Nonnull final Observable<R> lifecycle) { return new LifecycleTransformer<>(lifecycle); } /** * Binds the given source to a lifecycle. * <p> * This method determines (based on the lifecycle sequence itself) when the source * should stop emitting items. It uses the provided correspondingEvents function to determine * when to unsubscribe. * <p> * Note that this is an advanced usage of the library and should generally be used only if you * really know what you're doing with a given lifecycle. * * @param lifecycle the lifecycle sequence * @param correspondingEvents a function which tells the source when to unsubscribe * @return a reusable {@link LifecycleTransformer} that unsubscribes the source during the Fragment lifecycle */ @Nonnull @CheckReturnValue public static <T, R> LifecycleTransformer<T> bind(@Nonnull Observable<R> lifecycle, @Nonnull final Function<R, R> correspondingEvents) { checkNotNull(lifecycle, "lifecycle == null"); checkNotNull(correspondingEvents, "correspondingEvents == null"); return bind(takeUntilCorrespondingEvent(lifecycle.share(), correspondingEvents)); } 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); } } 

最终执行到了 RxLifecycle 这个类源码里面的最后的两个方法!

4:takeUntilCorrespondingEvent()

takeUntilCorrespondingEvent这个方法内容较多,首先分析第一个,combineLatest操作符,这个操作符是指 将传进来的BehaviorSubject的事件进行了一次分割;假设我们现在在onCreate()方法里面进行RxLifecycle的绑定,那么这里的lifecycle.take(1).map(correspondingEvents)简单理解其对应的代码就是 RxLifecycleAndroid源码 里面的ACTIVITY_LIFECYCLE 中的,

 case CREATE: return ActivityEvent.DESTROY; 

另外,lifecycle.skip(1)意味着除去第一个(ActivityEvent.CREATE),保留剩下的ActivityEvent枚举值

new BiFunction<R, R, Boolean>这行代码是对属性值进行判断:对比结果是
false,false,fasle,false,true

最后,onErrorReturn和filter这两行代码分别是对异常的处理以及判断是否应该结束订阅、

final class Functions { 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; } //noinspection ThrowableResultOfMethodCallIgnored Exceptions.propagate(throwable); return false; } }; static final Predicate<Boolean> SHOULD_COMPLETE = new Predicate<Boolean>() { @Override public boolean test(Boolean shouldComplete) throws Exception { return shouldComplete; } }; static final Function<Object, Completable> CANCEL_COMPLETABLE = new Function<Object, Completable>() { @Override public Completable apply(Object ignore) throws Exception { return Completable.error(new CancellationException()); } }; private Functions() { throw new AssertionError("No instances!"); } } 

综上:本次订阅,当Activity走到onStart生命周期时,为false,订阅不会取消,直到onDestroy,为true,订阅取消

5:最后调用的方法

根据逻辑,上面最终调用了下面的代码:

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

可以看到,这里最终生成了一个LifecycleTransformer。

源码逻辑总结:

A:继承了RxAppCompatActivity的子类Activity,在每个生命的周期里,BehaviorSubject发射相对应的事件
B:bind方法主要是做赋值、匹配、判断
C:LifecycleTransformer内部进行takeUntil操作符,如果是true,就终止订阅,反之

如果这篇文章对你有帮助,希望各位看官留下宝贵的star,谢谢。

Ps:著作权归作者所有,转载请注明作者, 商业转载请联系作者获得授权,非商业转载请注明出处(开头或结尾请添加转载出处,添加原文url地址),文章请勿滥用,也希望大家尊重笔者的劳动成果。

原文链接:https://yq.aliyun.com/articles/657486
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章