動手實現(xiàn)一個輕量級無侵入性的RxJava自動注銷庫RxLifecycle

*本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家發(fā)布

一. 概述

RxLifecycle是一個輕量級,侵入性低的RxJava注銷管理庫.他不會改變原有項目Activity的繼承結構,輕松實現(xiàn)RxJava在Android平臺下的自動注銷,甚至你在自定義view的時候使用RxJava都能輕松完整自動注銷功能.如果你的項目在開發(fā)中期想要引入RxJava相關的自動注銷庫,這個庫將是你不錯的選擇,原因就在他的入侵性低.

項目地址: 歡迎star

https://github.com/dhhAndroid/RxLifecycle

gradle 依賴:

compile 'com.dhh:rxlifecycle:1.0'

二. 使用方法

把RxLifecycle注入到Activity,請放心,RxLifecycle庫并不會引用with()傳進去的上下文引用,所以不用反注銷,不會造成內存泄漏,這塊的邏輯類似Glide的處理方式,在原理解析部分會講到.以下兩種注入方式,實現(xiàn)一種即可:

如果你有一個BaseActivity,僅需在BaseActivity的onCreate方法里注入RxLifecycle:


        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            RxLifecycle.injectRxLifecycle(this);
    
        }

既然你有一個BaseActivity,可以將RxLifecycle代碼封裝一下:


        private <T> LifecycleTransformer<T> bindToLifecycle() {
            return RxLifecycle.with(this).bindToLifecycle();
        }
    
        private <T> LifecycleTransformer<T> bindOnDestroy() {
            return RxLifecycle.with(this).bindOnDestroy();
        }
    
        private <T> LifecycleTransformer<T> bindUntilEvent(ActivityEvent event) {
            return RxLifecycle.with(this).bindUntilEvent(event);
        }

        //use
        @Override
        protected void onStart() {
            super.onStart();
            Observable.just(1)
                    //use       
                    .compose(bindToLifecycle())
                    .subscribe();
        }

或者你已經(jīng)有了繼承Application的操作,你也可以這樣注入RxLifecycle:


        public class RxLifecycleAPP extends Application {
            @Override
            public void onCreate() {
                super.onCreate();
                registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
                    @Override
                    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                        RxLifecycle.injectRxLifecycle(activity);
                    }
                    //other mothods
                });
            }
        }


注意:

1. 以上兩種注入RxLifecycle的方式,實現(xiàn)一種就可以了,同時實現(xiàn)也沒有問題,如果你樂意!

2. 如果你不在Activity的"onPause"生命周期及其以后的生命周期里訂閱一個Observable,注入RxLifecycle的步驟可以省略不做.如果在Activity的"onPause"生命周期及其以后的生命周期里訂閱一個Observable,并且使用RxLifecycle.with(this).bindToLifecycle(),必須進行RxLifecycle注入步奏.在原理解析部分會說明導致這種問題的原因.代碼示例:


    @Override
    protected void onPause() {
        super.onPause();
        Observable.just("dhhAndroid")
                //其他方式綁定不用預先注入
                .compose(RxLifecycle.with(this).<String>bindOnDestroy())
                .subscribe();
        Observable.just(1)
                //在onPause及其以后生命周期,使用bindToLifecycle()必須先注入RxLifecycle
                .compose(RxLifecycle.with(this).<Integer>bindToLifecycle())
                .subscribe();
    }

3. 為了簡化和保險,可以忽略第二條,全部注入,第二條就當我在瞎BB......

在Activity和Fragment中使用:

僅僅需要在你原先的Observable事件流上用compose操作符加上如下代碼:


        Observable.timer(10, TimeUnit.SECONDS)
                //自動判斷生命周期
                .compose(RxLifecycle.with(this).<Long>bindToLifecycle())
                .subscribe();
                
        Observable.timer(10, TimeUnit.SECONDS)
                //當activity onStop 注銷
                .compose(RxLifecycle.with(this).<Long>bindUntilEvent(ActivityEvent.onStop))
                .subscribe();
        Observable.just("dhhAndroid")
                //當activity onDestroy 注銷
                .compose(RxLifecycle.with(this).<String>bindOnDestroy())
                .subscribe();

RxLifecycle.with(),with方法可以接收的參數(shù)類型有Activity,Context(說明:這個Context必須能強轉成Activity),View(暫不支持V7包下的AppCompatXXXView),Fragment,V4.Fragment等.

在自定義view用使用

如果你在自定義view的時候里面使用的RxJava,以及View內部有retrofit+RxJava的網(wǎng)絡訪問,已經(jīng)RxJava操作的耗時數(shù)據(jù)轉換,同樣支持一行代碼管理RxJava自動注銷,確保你的view不是繼承自AppCompatXXXView,暫不支持.用法和在activity和fragment里一樣:


        public class MyView extends View {
            //other...

            public void doSomething(){
                Observable.timer(10, TimeUnit.SECONDS)
                        //自動判斷生命周期
                        .compose(RxLifecycle.with(this).<Long>bindToLifecycle())
                        .subscribe();
                        
                Observable.timer(10, TimeUnit.SECONDS)
                        //當activity onStop 注銷
                        .compose(RxLifecycle.with(this).<Long>bindUntilEvent(ActivityEvent.onStop))
                        .subscribe();
                Observable.just("dhhAndroid")
                        //當activity onDestroy 注銷
                        .compose(RxLifecycle.with(this).<String>bindOnDestroy())
                        .subscribe();
                ....
            }       
        }


在其他層使用

在MVP架構或者其他地方使用RxLifecycle時,僅需確保所使用的地方能獲取到一個能轉化成Activity的Context即可. 項目里我寫了一個with重載方法可傳入任意對象,只要能轉化成Context,或者通過反射能獲取到所傳對象的成員變量有能轉化成Context(Activity),也可實現(xiàn)RxJava生命周期自動綁定,但考慮到性能問題暫未開放(private方法).你可以根據(jù)這用思路,結合自己項目進行擴展.代碼如下:


    private static LifecycleManager with(Object object) {
        if (object instanceof Context) {
            return with((Context) object);
        }
        for (Field field : object.getClass().getDeclaredFields()) {
            try {
                field.setAccessible(true);
                Object value = field.get(object);
                if (value instanceof Context) {
                    return with((Context) value);
                }

            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        throw new ClassCastException(object.getClass().getSimpleName() + " can\'t convert Context !");
    }

三 . 原理解析(開始秀操作了,別打我)

首先聊一下寫這個庫的初衷,首先RxJava的確是一個優(yōu)秀的異步操作庫,這也就導致了在Android平臺上使用時,內存泄漏的問題.所以要在適當?shù)臅r候(一般是RxJava代碼依托的Activity視圖onDestroy的時候),注銷掉Observable的事件任務.那么我們先聊聊RxJava的注銷都有那些方式,以及什么條件能觸發(fā)注銷.

1.生成Subscription,在Activity的onDestroy時注銷:

    private Subscription mSubscription;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        mSubscription = Observable.just(1).subscribe();
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(mSubscription!=null&&!mSubscription.isUnsubscribed()) {
            mSubscription.unsubscribe();
        }
    }

這中方式算是傳統(tǒng)方式,比較笨重,如果界面中有多個網(wǎng)絡請求,或者RxBus接收數(shù)據(jù)的話,這樣注銷太累了.

2. 條件觸發(fā),取消訂閱關系,取消Observable事件流任務.

這里面條件觸發(fā)的就很多了,比如take系列的操作符,都是在滿足條件的時候開始訂閱,或者取消訂閱. 以及在 subscriber的onNext()方法中滿足某些條件都能取消訂閱,還有一個另類的方法,就是是Observable的事件流執(zhí)行過程中拋異常,也可以達到注銷的目的,實例代碼:

        Observable.just(1, 23, 434, 5454, 343, 346, 56, 67, 4, -1)
                //取前五個就注銷
                .take(5)
                //直到條件滿足,注銷
                .takeUntil(new Func1<Integer, Boolean>() {
                    @Override
                    public Boolean call(Integer integer) {
                        return integer > 66666;
                    }
                })
                //直到另外一個Observable發(fā)送數(shù)據(jù)就注銷,本庫主要用的這個操作符
                .takeUntil(Observable.just(1))
                .first(new Func1<Integer, Boolean>() {
                    @Override
                    public Boolean call(Integer integer) {
                        return integer == 111;
                    }
                })
                .map(new Func1<Integer, Integer>() {
                    @Override
                    public Integer call(Integer integer) {
                        if (integer < 0) {
                            //拋異常注銷,這種用法在我另外一個庫RxProgressManager使用到
                            throw new RuntimeException("數(shù)據(jù)不能小于0");
                        }
                        return integer;
                    }
                })
                .subscribe(new Subscriber<Integer>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(Integer integer) {
                        if (integer == 666) {
                            //當滿足條件注銷
                            unsubscribe();
                        }
                    }
                });

本庫主要利用takeUntil(otherObservable)實現(xiàn),takeUntil操作符演示圖:

takeUntil
takeUntil

一旦otherObservable發(fā)送數(shù)據(jù)原Observable就取消訂閱.所以我們要做的就是將Activity的生命周期信息通過Observable包裝成otherObservable,然后跟隨生命周期發(fā)送信息,到達到我們需要的生命周期的時候(比如onDestroy)取消訂閱.幸好RxJava已經(jīng)為我們實現(xiàn)了這種功能的Subject,Subject extends Observable implement Observer,是一種Observable與 subscriber之間的橋梁:

public abstract class Subject<T, R> extends Observable<R> implements Observer<T> {
    protected Subject(OnSubscribe<R> onSubscribe) {
        super(onSubscribe);
    }
    public abstract boolean hasObservers();

    public final SerializedSubject<T, R> toSerialized() {
        if (getClass() == SerializedSubject.class) {
            return (SerializedSubject<T, R>)this;
        }
        return new SerializedSubject<T, R>(this);
    }
}

RxJava已經(jīng)默認實現(xiàn)了幾種XXXSubject,其他的我就不介紹了,只介紹本文要用到的 BehaviorSubject ,他的特點是當有subscriber訂閱BehaviorSubject時,BehaviorSubject都將這個subscriber訂閱之前發(fā)射的最后一個數(shù)據(jù)一并發(fā)給他,如果BehaviorSubject已經(jīng)執(zhí)行onCompleted或者onError,那么將會把onCompleted或者onError通知發(fā)送給這個Subscriber.

BehaviorSubject
  // observer will receive all 4 events (including "default").
  BehaviorSubject<Object> subject = BehaviorSubject.create("default");
  subject.subscribe(observer);
  subject.onNext("one");
  subject.onNext("two");
  subject.onNext("three");

  // observer will receive the "one", "two" and "three" events, but not "default" and "zero"
  BehaviorSubject<Object> subject = BehaviorSubject.create("default");
  subject.onNext("zero");
  subject.onNext("one");
  subject.subscribe(observer);
  subject.onNext("two");
  subject.onNext("three");

  // observer will receive only onCompleted
  BehaviorSubject<Object> subject = BehaviorSubject.create("default");
  subject.onNext("zero");
  subject.onNext("one");
  subject.onCompleted();
  subject.subscribe(observer);

  // observer will receive only onError
  BehaviorSubject<Object> subject = BehaviorSubject.create("default");
  subject.onNext("zero");
  subject.onNext("one");
  subject.onError(new RuntimeException("error"));
  subject.subscribe(observer);

那么我們在Activity或Fragment中就可以這樣(由于Fragment依托于Activity,我在本項目里,Fragment的生命周期認為是和Activity一樣的,沒有處理Fragment比Activity多的生命周期回調):


public class MainActivity extends AppCompatActivity {
    private final BehaviorSubject<ActivityEvent> lifecycleSubject = BehaviorSubject.create();
    
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        lifecycleSubject.onNext(ActivityEvent.onCreate);
        super.onCreate(savedInstanceState);
        Observable.just(1)
                .takeUntil(lifecycleSubject.first(new Func1<ActivityEvent, Boolean>() {
                    @Override
                    public Boolean call(ActivityEvent event) {
                        return event==ActivityEvent.onDestory;
                    }
                }))
                .subscribe();
    }

    @Override
    public void onStart() {
        lifecycleSubject.onNext(ActivityEvent.onStart);
        super.onStart();
    }

    @Override
    public void onResume() {
        lifecycleSubject.onNext(ActivityEvent.onResume);
        super.onResume();
    }

    @Override
    public void onPause() {
        lifecycleSubject.onNext(ActivityEvent.onPause);
        super.onPause();
    }

    @Override
    public void onStop() {
        lifecycleSubject.onNext(ActivityEvent.onStop);
        super.onStop();
    }

    @Override
    public void onDestroy() {
        lifecycleSubject.onNext(ActivityEvent.onDestory);
        super.onDestroy();
    }
}

ActivityEvent是一個枚舉,列舉出了Activity的生命周期:

public enum ActivityEvent {
    onCreate,
    onStart,
    onResume,
    onPause,
    onStop,
    onDestory,
}

這樣我們通過lifecycleSubject將Activity的生命周期一一發(fā)出,用takeUntil將其作為otherObservable連接到原Observable上,在通過first操作符,直到接收到我們指定的生命周期(上面指定的是onDestroy),原Observable若沒注銷,就會注銷.first操作符演示圖如下(和takeFirst操作符類似):

first
first
takeFirst

這樣我們已經(jīng)完成了通過Activity生命周期注銷RxJava的核心原理,那么我們是不是可以將這個固定操作封裝成我們自己的操作符?當然是可以了, RxJava提供了兩種自定義操作符類型,一種是Observable.Operator,通過lift()操作符將自定義操作符連接到Observable上,這種操作符是對數(shù)據(jù)做轉換的,不適用我們的應用場景,我們是要對Observable做變換,我們需要使用第二種自定義操作符Observable.Transformer,它是對上游的Observable做變換:

public class LifecycleTransformer<T> implements Observable.Transformer<T, T> {
    private Observable<ActivityEvent> lifecycleObservable;
    private ActivityEvent activityEvent;

    LifecycleTransformer(Observable<ActivityEvent> lifecycleObservable, ActivityEvent activityEvent) {
        this.lifecycleObservable = lifecycleObservable;
        this.activityEvent = activityEvent;
    }

    @Override
    public Observable<T> call(Observable<T> sourceObservable) {
        return sourceObservable.takeUntil(getLifecycleObservable());
    }

    @NonNull
    private Observable<?> getLifecycleObservable() {
        lifecycleObservable.takeFirst(new Func1<ActivityEvent, Boolean>() {
            @Override
            public Boolean call(ActivityEvent event) {
                return activityEvent == event;
            }
        });
    }
}

這個時候我們就可以使用 compose操作符將我們自定義的LifecycleTransformer連接到原來的Observable上:

        Observable.just(1)
                .compose(new LifecycleTransformer<Integer>(lifecycleSubject,ActivityEvent.onDestory))
                .subscribe();

實現(xiàn)的功能和上面寫法一模一樣,那么我們定義一個接口LifecycleManager用于生成這些LifecycleTransformer:


public interface LifecycleManager {

    Observable<ActivityEvent> getLifecycle();

    <T> LifecycleTransformer<T> bindUntilEvent(ActivityEvent activityEvent);

    <T> LifecycleTransformer<T> bindToLifecycle();

    <T> LifecycleTransformer<T> bindOnDestroy();
}

接口里一共提供了4個方法:

  • getLifecycle():用于獲取提供生命周期的Observable,也就是上文提到的 lifecycleSubject(就是BehaviorSubject)
  • bindUntilEvent(ActivityEvent activityEvent):根據(jù)傳入的生命周期,生成指定的LifecycleTransformer,就是將原Observable綁定到指定Activity生命周期.
  • bindToLifecycle() : 這個是根據(jù)原Observable訂閱與那個生命周期,轉化到它應該在那個生命周期注銷,比如在onCreate訂閱就在OnDestroy注銷,在onStart訂閱就在onStop注銷,在onResume訂閱就在onPause注銷,這個適用于在界面可見的時候開始干什么事,界面不可見的時候停止干什么事情,比如輪播圖.
  • bindOnDestroy():直接綁定到當Activity界面銷毀的時候Observable注銷,這個是bindUntilEvent(ActivityEvent activityEvent)的一種情況,因為用的比較多,我就多寫了這個.

下面介紹一下這個 bindToLifecycle()如何實現(xiàn),直接上代碼:


    public class LifecycleTransformer<T> implements Observable.Transformer<T, T> {
    private Observable<ActivityEvent> lifecycleObservable;
    
    LifecycleTransformer(Observable<ActivityEvent> lifecycleObservable) {
        this.lifecycleObservable = lifecycleObservable.share();
    }

    @Override
    public Observable<T> call(Observable<T> sourceObservable) {
        return sourceObservable.takeUntil(getLifecycleObservable());
    }

    @NonNull
    private Observable<?> getLifecycleObservable() {
        return Observable.combineLatest(lifecycleObservable.first().map(ACTIVITY_LIFECYCLE),
                lifecycleObservable.skip(1), new Func2<ActivityEvent, ActivityEvent, Boolean>() {
                    @Override
                    public Boolean call(ActivityEvent activityEvent, ActivityEvent event) {
                        return activityEvent == event;
                    }
                })
                .takeFirst(new Func1<Boolean, Boolean>() {
                    @Override
                    public Boolean call(Boolean aBoolean) {
                        return aBoolean;
                    }
                });
    }


    // 用于生命周期轉化
    private static final Func1<ActivityEvent, ActivityEvent> ACTIVITY_LIFECYCLE =
            new Func1<ActivityEvent, ActivityEvent>() {
                @Override
                public ActivityEvent call(ActivityEvent lastEvent) {
                    switch (lastEvent) {
                        case onCreate:
                            return ActivityEvent.onDestory;
                        case onStart:
                            return ActivityEvent.onStop;
                        case onResume:
                            return ActivityEvent.onPause;
                        case onPause:
                            return ActivityEvent.onStop;
                        case onStop:
                            return ActivityEvent.onDestory;
                        case onDestory:
                            throw new IllegalStateException("Cannot injectRxLifecycle to Activity lifecycle when outside of it.");
                        default:
                            throw new UnsupportedOperationException("Binding to " + lastEvent + " not yet implemented");
                    }
                }
            };
}

首先構造方法里,這次我們只需要拿到lifecycleSubject(lifecycleObservable)即可,不用在傳入ActivityEvent,通過share操作符,是這個lifecycleObservable可以有多個Subscriber.由于這個lifecycleObservable 其實就是BehaviorSubject,上文已經(jīng)介紹,當有訂閱者時,他會把他被訂閱之前最后一個事件發(fā)給這個訂閱者,我們通過first操作符,就可以拿到原Observable訂閱的時候是在那個生命周期訂閱的,然后通過map操作符將訂閱發(fā)生的生周期轉化出應該注銷的生命周期,這樣注銷的生命周期我們就有了,這樣就和構造方法傳入兩個參數(shù)的邏輯基本一樣了.

再通過combineLatest操作符將轉化生命周期的Observable(lifecycleObservable.first().map(ACTIVITY_LIFECYCLE))和發(fā)射生命周期的Observable(lifecycleObservable.skip(1))聯(lián)合起來,再通過takeFirst過濾出指定生命周期的后發(fā)送數(shù)據(jù),從而注銷原Observable.

將以上種構造方法合并到一個LifecycleTransformer里后代碼如下:

public class LifecycleTransformer<T> implements Observable.Transformer<T, T> {
    private Observable<ActivityEvent> lifecycleObservable;
    private ActivityEvent activityEvent;

    LifecycleTransformer(Observable<ActivityEvent> lifecycleObservable) {
        this.lifecycleObservable = lifecycleObservable.share();
    }

    LifecycleTransformer(Observable<ActivityEvent> lifecycleObservable, ActivityEvent activityEvent) {
        this.lifecycleObservable = lifecycleObservable;
        this.activityEvent = activityEvent;
    }

    @Override
    public Observable<T> call(Observable<T> sourceObservable) {
        return sourceObservable.takeUntil(getLifecycleObservable());
    }

    @NonNull
    private Observable<?> getLifecycleObservable() {
        if (activityEvent != null) {
            lifecycleObservable.takeFirst(new Func1<ActivityEvent, Boolean>() {
                @Override
                public Boolean call(ActivityEvent event) {
                    return activityEvent == event;
                }
            });
        }
        return Observable.combineLatest(lifecycleObservable.first().map(ACTIVITY_LIFECYCLE),
                lifecycleObservable.skip(1), new Func2<ActivityEvent, ActivityEvent, Boolean>() {
                    @Override
                    public Boolean call(ActivityEvent activityEvent, ActivityEvent event) {
                        return activityEvent == event;
                    }
                })
                .takeFirst(new Func1<Boolean, Boolean>() {
                    @Override
                    public Boolean call(Boolean aBoolean) {
                        return aBoolean;
                    }
                });
    }


    // 用于生命周期轉化
    private static final Func1<ActivityEvent, ActivityEvent> ACTIVITY_LIFECYCLE =
            new Func1<ActivityEvent, ActivityEvent>() {
                @Override
                public ActivityEvent call(ActivityEvent lastEvent) {
                    switch (lastEvent) {
                        case onCreate:
                            return ActivityEvent.onDestory;
                        case onStart:
                            return ActivityEvent.onStop;
                        case onResume:
                            return ActivityEvent.onPause;
                        case onPause:
                            return ActivityEvent.onStop;
                        case onStop:
                            return ActivityEvent.onDestory;
                        case onDestory:
                            throw new IllegalStateException("Cannot injectRxLifecycle to Activity lifecycle when outside of it.");
                        default:
                            throw new UnsupportedOperationException("Binding to " + lastEvent + " not yet implemented");
                    }
                }
            };
}

也是由于這個 生命周期轉化的問題,導致在onPause及其以后的生命周期里訂閱一個Observable的時候,需要事先注入RxLifecycle,下文會講到.

那么我們接下來要做的事情就是獲取和Activity一一對應的LifecycleManager了.

這一塊我借鑒的是Glide的做法:Glide.with(activity):

我們知道當Fragment通過FragmentManager加入到Activity中后,具有和activity基本相同的生命周期(忽略其他),那么我們通過這個Fragment發(fā)送activity的使命周期事件,同樣能達到預期的效果,再讓這個Fragment實現(xiàn) LifecycleManager 接口不就行了,上一波代碼:

public class LifecycleFragment extends Fragment implements LifecycleManager {
    private final BehaviorSubject<ActivityEvent> lifecycleSubject;

    public LifecycleFragment() {
        lifecycleSubject = BehaviorSubject.create();
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        lifecycleSubject.onNext(ActivityEvent.onCreate);
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onStart() {
        lifecycleSubject.onNext(ActivityEvent.onStart);
        super.onStart();
    }

    @Override
    public void onResume() {
        lifecycleSubject.onNext(ActivityEvent.onResume);
        super.onResume();
    }

    @Override
    public void onPause() {
        lifecycleSubject.onNext(ActivityEvent.onPause);
        super.onPause();
    }

    @Override
    public void onStop() {
        lifecycleSubject.onNext(ActivityEvent.onStop);
        super.onStop();
    }

    @Override
    public void onDestroy() {
        lifecycleSubject.onNext(ActivityEvent.onDestory);
        super.onDestroy();
    }

    @Override
    public Observable<ActivityEvent> getLifecycle() {
        return lifecycleSubject.asObservable();
    }

    @Override
    public <T> LifecycleTransformer<T> bindUntilEvent(final ActivityEvent activityEvent) {
        return new LifecycleTransformer<>(lifecycleSubject, activityEvent);
    }

    @Override
    public <T> LifecycleTransformer<T> bindToLifecycle() {
        return new LifecycleTransformer<>(lifecycleSubject);
    }

    @Override
    public <T> LifecycleTransformer<T> bindOnDestroy() {
        return bindUntilEvent(ActivityEvent.onDestory);
    }
}

這樣我們就可以通過這個**LifecycleFragment ** 既能獲取到Activity的生命周期,又能獲取到 各種 LifecycleTransformer.

這個時候我們就需要獲取這個和Activity一一對應的**LifecycleFragment **即 LifecycleManager:

public class RxLifecycle {
    private static final String FRAGMENT_TAG = "lifecycle_tag";

    public static LifecycleManager with(Activity activity) {
        FragmentManager fm = activity.getFragmentManager();
        Fragment fragment = fm.findFragmentByTag(FRAGMENT_TAG);
        if (fragment == null) {
            fragment = new LifecycleFragment();
            fm.beginTransaction().add(fragment, FRAGMENT_TAG).commitAllowingStateLoss();
            fm.executePendingTransactions();
        }
        return (LifecycleManager) fragment;
    }

通過FragmentManager 將一個空的LifecycleFragment 附加TAG添加到Activity中,如果再次調用同過TAG拿到.這樣我們就拿到了LifecycleManager,就可以獲取各種LifecycleTransformer了.

這時候我們就要想那個在onPause以后以后訂閱的Observable使用bindToLifecycle 為什么要先注入RxLifecycle的問題:

若果你在onPause之前,這個Activity都沒有使用過RxLifecycle,這個是個這個界面并沒有加入這個空的LifecycleFragment,導致在onPause的時候首次調用會出現(xiàn)LifecycleFragment回調的生命周期是onCreate->onStart->onPause->onStop(沒有onResume,是因為這個Fragment在創(chuàng)建的時候界面已經(jīng)不可見了,所以不會回調這個),所以在使用bindToLifecycle()的時候,生命周期的轉化會出問題.自行補腦吧,不詳細分析了.

所以我不得不加入一個預先注入的方法,在Activity的onCreate方法調用:

    /**
     * @param context ensure context can be cast {@link Activity}
     */
    public static void injectRxLifecycle(Context context) {
        with(context);
    }

其實最后調用的還是 with(activity)的方法,就是先把這個LifecycleFragment和Activity綁定.保證在調用bindToLifecycle()的時候,生命周期轉化正常.如果你有更好的處理方法,請及時告知我,萬分感謝!

上文說到,這個RxLifecycle庫,也可以在自定義view中使用,其實也簡單,就是通過view.getContext(),獲取上下文,那view是放在Activity上,那個這個上下文必然是Activity,然而實事還是打臉了,V7包下的AppCompatXXXView,獲取的上下文是一個TintContextWrapper,不能強轉成Activity,我的內心是崩潰的,哪位大佬知道怎么班,快告訴我,膝蓋送上!

RxLifecycle類全部代碼:

public class RxLifecycle {
    private static final String FRAGMENT_TAG = "lifecycle_tag";

    /**
     * @param context ensure context can be cast {@link Activity}
     */
    public static void injectRxLifecycle(Context context) {
        with(context);
    }

    public static LifecycleManager with(Activity activity) {
        if (activity instanceof FragmentActivity) {
            return with((FragmentActivity) activity);
        }
        FragmentManager fm = activity.getFragmentManager();
        Fragment fragment = fm.findFragmentByTag(FRAGMENT_TAG);
        if (fragment == null) {
            fragment = new LifecycleFragment();
            fm.beginTransaction().add(fragment, FRAGMENT_TAG).commitAllowingStateLoss();
            fm.executePendingTransactions();
        }
        return (LifecycleManager) fragment;
    }

    private static LifecycleManager with(FragmentActivity activity) {
        android.support.v4.app.FragmentManager fm = activity.getSupportFragmentManager();
        android.support.v4.app.Fragment fragment = fm.findFragmentByTag(FRAGMENT_TAG);
        if (fragment == null) {
            fragment = new LifecycleV4Fragment();
            fm.beginTransaction().add(fragment, FRAGMENT_TAG).commitNowAllowingStateLoss();
        }

        return (LifecycleManager) fragment;
    }

    public static LifecycleManager with(Fragment fragment) {
        return with(fragment.getActivity());
    }

    public static LifecycleManager with(android.support.v4.app.Fragment fragment) {
        return with(fragment.getActivity());
    }

    /**
     * @param context ensure context can be cast {@link Activity}
     */
    public static LifecycleManager with(Context context) {
        if (context instanceof AppCompatActivity) {
            return with((FragmentActivity) context);
        }
        if (context instanceof Activity) {
            return with((Activity) context);
        }
        throw new ClassCastException(context.getClass().getSimpleName() + " can\'t cast Activity !");
    }

    public static LifecycleManager with(View view) {
        return with(view.getContext());
    }


    private static void injectRxLifecycle(Object object) {
        if (object instanceof View) {
            with((View) object);
        } else {
            with(object);
        }
    }

    private static LifecycleManager with(Object object) {
        if (object instanceof Context) {
            return with((Context) object);
        }
        for (Field field : object.getClass().getDeclaredFields()) {
            try {
                field.setAccessible(true);
                Object value = field.get(object);
                if (value instanceof Context) {
                    return with((Context) value);
                }

            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        throw new ClassCastException(object.getClass().getSimpleName() + " can\'t convert Context !");
    }

}

About me

項目地址: https://github.com/dhhAndroid/RxLifecycle

您的一個star是對我最大的鼓勵!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末浑彰,一起剝皮案震驚了整個濱河市闸拿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌伤溉,老刑警劉巖仰美,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蔚晨,居然都是意外死亡乍钻,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門铭腕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來银择,“玉大人,你說我怎么就攤上這事累舷『瓶迹” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵被盈,是天一觀的道長析孽。 經(jīng)常有香客問我搭伤,道長,這世上最難降的妖魔是什么袜瞬? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任怜俐,我火速辦了婚禮,結果婚禮上吞滞,老公的妹妹穿的比我還像新娘佑菩。我一直安慰自己,他們只是感情好裁赠,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布殿漠。 她就那樣靜靜地躺著,像睡著了一般佩捞。 火紅的嫁衣襯著肌膚如雪绞幌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天一忱,我揣著相機與錄音莲蜘,去河邊找鬼。 笑死帘营,一個胖子當著我的面吹牛票渠,可吹牛的內容都是我干的。 我是一名探鬼主播芬迄,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼问顷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了禀梳?” 一聲冷哼從身側響起杜窄,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎算途,沒想到半個月后塞耕,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡嘴瓤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年扫外,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片廓脆。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡畏浆,死狀恐怖,靈堂內的尸體忽然破棺而出狞贱,到底是詐尸還是另有隱情刻获,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站蝎毡,受9級特大地震影響厚柳,放射性物質發(fā)生泄漏。R本人自食惡果不足惜沐兵,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一别垮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧扎谎,春花似錦碳想、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至预吆,卻和暖如春龙填,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拐叉。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工岩遗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人凤瘦。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓宿礁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蔬芥。 傳聞我的和親對象是個殘疾皇子梆靖,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內容