diff --git a/autodispose-android-archcomponents/src/androidTest/java/com/uber/autodispose/android/lifecycle/AndroidLifecycleScopeProviderTest.java b/autodispose-android-archcomponents/src/androidTest/java/com/uber/autodispose/android/lifecycle/AndroidLifecycleScopeProviderTest.java index 9e9b44e0b..f0f44a84f 100644 --- a/autodispose-android-archcomponents/src/androidTest/java/com/uber/autodispose/android/lifecycle/AndroidLifecycleScopeProviderTest.java +++ b/autodispose-android-archcomponents/src/androidTest/java/com/uber/autodispose/android/lifecycle/AndroidLifecycleScopeProviderTest.java @@ -24,11 +24,11 @@ import com.uber.autodispose.AutoDispose; import com.uber.autodispose.LifecycleEndedException; import com.uber.autodispose.test.RecordingObserver; -import io.reactivex.disposables.Disposable; -import io.reactivex.subjects.PublishSubject; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import io.reactivex.disposables.Disposable; +import io.reactivex.subjects.PublishSubject; import static com.google.common.truth.Truth.assertThat; @@ -165,6 +165,73 @@ lifecycle.emit(Lifecycle.Event.ON_DESTROY); } + @Test @UiThreadTest public void observable_createPause() { + final RecordingObserver o = new RecordingObserver<>(LOGGER); + final PublishSubject subject = PublishSubject.create(); + + // Spin it up + TestAndroidLifecycleScopeProvider lifecycle = new TestAndroidLifecycleScopeProvider(); + lifecycle.emit(Lifecycle.Event.ON_CREATE); + subject.to(AutoDispose.with(AndroidLifecycleScopeProvider + .from(lifecycle, Lifecycle.Event.ON_PAUSE)) + .forObservable()) + .subscribe(o); + lifecycle.emit(Lifecycle.Event.ON_START); + lifecycle.emit(Lifecycle.Event.ON_RESUME); + + Disposable d = o.takeSubscribe(); + o.assertNoMoreEvents(); // No initial value. + + subject.onNext(0); + assertThat(o.takeNext()).isEqualTo(0); + + subject.onNext(1); + assertThat(o.takeNext()).isEqualTo(1); + + // We should stop here + lifecycle.emit(Lifecycle.Event.ON_PAUSE); + subject.onNext(2); + o.assertNoMoreEvents(); + + lifecycle.emit(Lifecycle.Event.ON_STOP); + lifecycle.emit(Lifecycle.Event.ON_DESTROY); + } + + @Test @UiThreadTest public void observable_resumeDestroy() { + final RecordingObserver o = new RecordingObserver<>(LOGGER); + final PublishSubject subject = PublishSubject.create(); + + // Spin it up + TestAndroidLifecycleScopeProvider lifecycle = new TestAndroidLifecycleScopeProvider(); + lifecycle.emit(Lifecycle.Event.ON_CREATE); + lifecycle.emit(Lifecycle.Event.ON_START); + lifecycle.emit(Lifecycle.Event.ON_RESUME); + subject.to(AutoDispose.with(AndroidLifecycleScopeProvider + .from(lifecycle, Lifecycle.Event.ON_DESTROY)) + .forObservable()) + .subscribe(o); + + Disposable d = o.takeSubscribe(); + o.assertNoMoreEvents(); // No initial value. + + subject.onNext(0); + assertThat(o.takeNext()).isEqualTo(0); + + subject.onNext(1); + assertThat(o.takeNext()).isEqualTo(1); + + lifecycle.emit(Lifecycle.Event.ON_PAUSE); + lifecycle.emit(Lifecycle.Event.ON_STOP); + + subject.onNext(2); + assertThat(o.takeNext()).isEqualTo(2); + + // We should stop here + lifecycle.emit(Lifecycle.Event.ON_DESTROY); + subject.onNext(3); + o.assertNoMoreEvents(); + } + @Test public void observable_offMainThread_shouldFail() { RecordingObserver o = new RecordingObserver<>(LOGGER); PublishSubject subject = PublishSubject.create(); diff --git a/autodispose-android-archcomponents/src/main/java/com/uber/autodispose/android/lifecycle/AndroidLifecycleScopeProvider.java b/autodispose-android-archcomponents/src/main/java/com/uber/autodispose/android/lifecycle/AndroidLifecycleScopeProvider.java index c98038b5a..aca5f735e 100644 --- a/autodispose-android-archcomponents/src/main/java/com/uber/autodispose/android/lifecycle/AndroidLifecycleScopeProvider.java +++ b/autodispose-android-archcomponents/src/main/java/com/uber/autodispose/android/lifecycle/AndroidLifecycleScopeProvider.java @@ -34,7 +34,7 @@ public final class AndroidLifecycleScopeProvider implements LifecycleScopeProvider { - private static final Function CORRESPONDING_EVENTS = + private static final Function DEFAULT_CORRESPONDING_EVENTS = new Function() { @Override public Lifecycle.Event apply(Lifecycle.Event lastEvent) throws Exception { switch (lastEvent) { @@ -54,30 +54,64 @@ public final class AndroidLifecycleScopeProvider } }; + private final Function correspondingEvents; + /** * Creates a {@link AndroidLifecycleScopeProvider} for Android LifecycleOwners. * - * @param owner the owner to scope for + * @param owner the owner to scope for. * @return a {@link AndroidLifecycleScopeProvider} against this owner. */ public static AndroidLifecycleScopeProvider from(LifecycleOwner owner) { return from(owner.getLifecycle()); } + /** + * Creates a {@link AndroidLifecycleScopeProvider} for Android LifecycleOwners. + * + * @param owner the owner to scope for. + * @param untilEvent the event until the scope is valid. + * @return a {@link AndroidLifecycleScopeProvider} against this owner. + */ + public static AndroidLifecycleScopeProvider from( + LifecycleOwner owner, + Lifecycle.Event untilEvent) { + return from(owner.getLifecycle(), untilEvent); + } + /** * Creates a {@link AndroidLifecycleScopeProvider} for Android Lifecycles. * - * @param lifecycle the lifecycle to scope for + * @param lifecycle the lifecycle to scope for. * @return a {@link AndroidLifecycleScopeProvider} against this lifecycle. */ public static AndroidLifecycleScopeProvider from(Lifecycle lifecycle) { return new AndroidLifecycleScopeProvider(lifecycle); } + /** + * Creates a {@link AndroidLifecycleScopeProvider} for Android Lifecycles. + * + * @param lifecycle the lifecycle to scope for. + * @param untilEvent the event until the scope is valid. + * @return a {@link AndroidLifecycleScopeProvider} against this lifecycle. + */ + public static AndroidLifecycleScopeProvider from( + Lifecycle lifecycle, + Lifecycle.Event untilEvent) { + return new AndroidLifecycleScopeProvider(lifecycle, untilEvent); + } + private final LifecycleEventsObservable lifecycleObservable; private AndroidLifecycleScopeProvider(Lifecycle lifecycle) { this.lifecycleObservable = new LifecycleEventsObservable(lifecycle); + this.correspondingEvents = DEFAULT_CORRESPONDING_EVENTS; + } + + private AndroidLifecycleScopeProvider(Lifecycle lifecycle, Lifecycle.Event untilEvent) { + this.lifecycleObservable = new LifecycleEventsObservable(lifecycle); + this.correspondingEvents = new UntilEventFunction(untilEvent); } @Override public Observable lifecycle() { @@ -85,10 +119,22 @@ private AndroidLifecycleScopeProvider(Lifecycle lifecycle) { } @Override public Function correspondingEvents() { - return CORRESPONDING_EVENTS; + return correspondingEvents; } @Override public Lifecycle.Event peekLifecycle() { return lifecycleObservable.getValue(); } + + private static class UntilEventFunction implements Function { + private final Lifecycle.Event untilEvent; + + UntilEventFunction(Lifecycle.Event untilEvent) { + this.untilEvent = untilEvent; + } + + @Override public Lifecycle.Event apply(Lifecycle.Event event) throws Exception { + return untilEvent; + } + } } diff --git a/sample/src/main/java/com/uber/autodispose/sample/MainActivity.java b/sample/src/main/java/com/uber/autodispose/sample/MainActivity.java index 1a6181bd7..396333439 100644 --- a/sample/src/main/java/com/uber/autodispose/sample/MainActivity.java +++ b/sample/src/main/java/com/uber/autodispose/sample/MainActivity.java @@ -16,15 +16,17 @@ package com.uber.autodispose.sample; +import android.arch.lifecycle.Lifecycle; import android.os.Bundle; +import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.util.Log; import com.uber.autodispose.AutoDispose; import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider; +import java.util.concurrent.TimeUnit; import io.reactivex.Observable; import io.reactivex.functions.Action; import io.reactivex.functions.Consumer; -import java.util.concurrent.TimeUnit; /** * Demo activity, shamelessly borrowed from the RxLifecycle sample @@ -35,7 +37,7 @@ public class MainActivity extends AppCompatActivity { private static final String TAG = "AutoDispose"; - @Override protected void onCreate(Bundle savedInstanceState) { + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, "onCreate()"); @@ -95,6 +97,21 @@ public class MainActivity extends AppCompatActivity { // `.forObservable` is necessary if you're compiling on JDK7 or below. // If you're using JDK8+, then you can safely remove it. .to(AutoDispose.with(AndroidLifecycleScopeProvider.from(this)).forObservable()) + .subscribe(new Consumer() { + @Override public void accept(Long num) throws Exception { + Log.i(TAG, "Started in onResume(), running until in onPause(): " + num); + } + }); + + // Setting a specific untilEvent, this should dispose in onDestroy. + Observable.interval(1, TimeUnit.SECONDS) + .doOnDispose(new Action() { + @Override public void run() throws Exception { + Log.i(TAG, "Disposing subscription from onResume() with untilEvent ON_DESTROY"); + } + }) + .to(AutoDispose.with(AndroidLifecycleScopeProvider.from(this, + Lifecycle.Event.ON_DESTROY)).forObservable()) .subscribe(new Consumer() { @Override public void accept(Long num) throws Exception { Log.i(TAG, "Started in onResume(), running until in onDestroy(): " + num); diff --git a/sample/src/main/kotlin/com/uber/autodispose/sample/KotlinActivity.kt b/sample/src/main/kotlin/com/uber/autodispose/sample/KotlinActivity.kt index c31a5b8d5..f29a31dce 100644 --- a/sample/src/main/kotlin/com/uber/autodispose/sample/KotlinActivity.kt +++ b/sample/src/main/kotlin/com/uber/autodispose/sample/KotlinActivity.kt @@ -16,6 +16,7 @@ package com.uber.autodispose.sample +import android.arch.lifecycle.Lifecycle import android.os.Bundle import android.support.v7.app.AppCompatActivity import android.util.Log @@ -70,6 +71,16 @@ class KotlinActivity : AppCompatActivity() { .subscribe { num -> Log.i(TAG, "Started in onResume(), running until in onPause(): " + num) } + + // Setting a specific untilEvent, this should dispose in onDestroy. + Observable.interval(1, TimeUnit.SECONDS) + .doOnDispose { + Log.i(TAG, "Disposing subscription from onResume() with untilEvent ON_DESTROY") + } + .autoDisposeWith(AndroidLifecycleScopeProvider.from(this, Lifecycle.Event.ON_DESTROY)) + .subscribe{ num -> + Log.i(TAG, "Started in onResume(), running until in onDestroy(): " + num) + } } override fun onPause() {