Last active
August 29, 2015 14:10
-
-
Save mr-archano/0d1c5885229229bed637 to your computer and use it in GitHub Desktop.
I didn't want to pollute the discussion started in RxAndroid/#12 (https://github.com/ReactiveX/RxAndroid/issues/12), so I drafted a solution that collects some of the neat ideas showcased in there.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // NOTE: `OperatorSubscribeUntil` class is borrowed from @dlew's PR (https://github.com/dlew/RxAndroid/blob/dlew/lifecycle-observable/rxandroid/src/main/java/rx/android/lifecycle/OperatorSubscribeUntil.java) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package rx.android; | |
| import rx.Observable; | |
| import rx.Subscriber; | |
| import rx.observers.SerializedSubscriber; | |
| /** | |
| * Returns an Observable that emits the items from the source Observable until another Observable | |
| * emits an item. | |
| * <p> | |
| * Unlike takeUntil, this choose to unsubscribe the parent rather than calling onComplete(). | |
| */ | |
| final class OperatorSubscribeUntil<T, R> implements Observable.Operator<T, T> { | |
| private final Observable<? extends R> other; | |
| public OperatorSubscribeUntil(final Observable<? extends R> other) { | |
| this.other = other; | |
| } | |
| @Override | |
| public Subscriber<? super T> call(final Subscriber<? super T> child) { | |
| final Subscriber<T> parent = new SerializedSubscriber<T>(child); | |
| other.unsafeSubscribe(new Subscriber<R>(child) { | |
| @Override | |
| public void onCompleted() { | |
| parent.unsubscribe(); | |
| } | |
| @Override | |
| public void onError(Throwable e) { | |
| parent.onError(e); | |
| } | |
| @Override | |
| public void onNext(R t) { | |
| parent.unsubscribe(); | |
| } | |
| }); | |
| return parent; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package rx.android; | |
| import rx.Observable; | |
| import rx.subjects.PublishSubject; | |
| import java.util.HashMap; | |
| import java.util.Map; | |
| public class EventDrivenUnsubscriber<E extends EventDrivenUnsubscriber.Event> { | |
| private final Map<E, PublishSubject<E>> subjects; | |
| public EventDrivenUnsubscriber() { | |
| this.subjects = new HashMap<E, PublishSubject<E>>(); | |
| } | |
| public <T> Operator<T, T> bindTo(E event) { | |
| PublishSubject<E> subject = subjects.get(event); | |
| if (subject == null) { | |
| subject = PublishSubject.create(); | |
| subjects.put(event, subject); | |
| } | |
| return new OperatorSubscribeUntil<T, E>(subject); | |
| } | |
| public void unsubscribeAll(E event) { | |
| PublishSubject<E> subject = subjects.get(event); | |
| if (subject != null) { | |
| subject.onNext(event); | |
| } | |
| } | |
| static class Event { | |
| private final String name; | |
| protected Event(String name) { | |
| this.name = name; | |
| } | |
| @Override | |
| public boolean equals(Object o) { | |
| if (this == o) return true; | |
| if (!(o instanceof Event)) return false; | |
| Event event = (Event) o; | |
| return name.equals(event.name); | |
| } | |
| @Override | |
| public int hashCode() { | |
| return name.hashCode(); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package rx.android; | |
| public class ActivityLifeCycleEvent extends EventDrivenUnsubscriber.Event { | |
| public static final ActivityLifeCycleEvent ON_PAUSE = new ActivityLifeCycleEvent("onPause()"); | |
| public static final ActivityLifeCycleEvent ON_RESUME = new ActivityLifeCycleEvent("onResume()"); | |
| // TODO add other relevant events here... | |
| private ActivityLifeCycleEvent(String name) { | |
| super(name); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package rx.android.samples; | |
| import android.app.Activity; | |
| import android.os.Bundle; | |
| import rx.Observable; | |
| import rx.android.ActivityLifeCycleEvent; | |
| import rx.android.EventDrivenUnsubscriber; | |
| public class FooActivity extends Activity { | |
| private final EventDrivenUnsubscriber<ActivityLifeCycleEvent> unsubscriber = new EventDrivenUnsubscriber<ActivityLifeCycleEvent>(); | |
| @Override | |
| protected void onCreate(Bundle savedInstanceState) { | |
| super.onCreate(savedInstanceState); | |
| Observable.just("wut wut") | |
| .lift(unsubscriber.bindTo(ActivityLifeCycleEvent.ON_PAUSE)) | |
| ...; | |
| } | |
| @Override | |
| protected void onPause() { | |
| super.onPause(); | |
| unsubscriber.unsubscribeAll(ActivityLifeCycleEvent.ON_PAUSE); | |
| } | |
| } |
If your biggest objection is having a single enum for both Activity and Fragment events, then there's a simple solution: two enums instead of one.
Or even better - just create ad-hoc enumeration via custom resource type annotations. Java enums are great, but this method avoids their overhead of using them when their class-based nature is redundant, and allows arbitrary number of new items to be appended from different places.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Delegating to
EventDrivenUnsubscriber<LifecycleEvent>is exactly the same as delegating toObservable<LifecycleEvent>, since in both cases you need to write all the lifecycle handling code yourself... it's just that one is a base class of RxJava and the other is a wrapper that does the same thing.Your solution still requires all the same extensions of fragment/activity to reduce boilerplate. Unless you're proposing that
EventDrivenUnsubscriberrequires people to write their own event system, at which point it's basically no better than not having any framework for this at all (e.g., why not just use aCompositeSubscription?).