diff --git a/README.md b/README.md index 9eeb349d7..4135c2627 100755 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ the relevant factory call + method for that type as a converter. In everyday use ```java myObservable .doStuff() - .to(AutoDispose.with(this).forObservable()) // The magic + .as(autoDisposable(this)) // The magic .subscribe(s -> ...); ``` @@ -29,25 +29,22 @@ scope - this helps prevent many classes of errors when an observable emits and i taken in the subscription are no longer valid. For instance, if a network request comes back after a UI has already been torn down, the UI can't be updated - this pattern prevents this type of bug. -### `with()` + `()` +### `autoDisposable()` -The main entry point is via static factory `with()` methods in the `AutoDispose` class. There are -three overloads: `Maybe`, `ScopeProvider`, and `LifecycleScopeProvider`. They return a -`ScopeHandler` object that's just intended to be an intermediary to route to the desired type -function (this is for better autocomplete in IDEs for the generics). +The main entry point is via static factory `autoDisposable()` methods in the `AutoDispose` class. +There are three overloads: `Maybe`, `ScopeProvider`, and `LifecycleScopeProvider`. They return an +`AutoDisposeConverter` object that implements all the RxJava `Converter` interfaces for use with +the `as()` operator in RxJava types. -For the relevant `type` methods, there is one per RxJava type (`forObservable()`, `forSingle()`, etc). -These return implementations of a converter `Function`, intended for use with the `to()` operator in RxJava -types. - -These work in tandem to create the regular AutoDispose flow. `AutoDispose.with(scope).forObservable()`. - -#### Maybe +#### Maybe (as a scope) The `Maybe` semantic is modeled after the `takeUntil()` operator, which accepts an `Observable` whose first emission is used as a notification to signal completion. This is is logically the -behavior of a `Maybe`, so we choose to make that explicit. All scopes eventually resolve to a single -`Maybe` that emits the end-of-scope notification. +behavior of a `Single`, so we choose to make that explicit. Scope providers may want to dynamically +indicate that a scope is "unbound" though, so we use a `Maybe` to indicate this via its completion. +All scopes in AutoDispose eventually resolve to a `Maybe` that emits the end-of-scope notification +in `onSuccess` or signals that execution is unbound via `onComplete`. `onError` will pass through to +the underlying subscription. #### Providers @@ -95,28 +92,17 @@ public interface ScopeProvider { This is particularly useful for objects with simple scopes ("stop when I stop") or very custom state that requires custom handling. -#### Plugins - -When a lifecycle has not started or has already ended, `AutoDispose` will send an error event with an - `OutsideLifecycleException` to downstream consumers. If you want to customize this behavior, you can use - `AutoDisposePlugins` to intercept these exceptions and rethrow something else or nothing at all. - -### Behavior - -The created observer encapsulates the parameters of `around` to create a disposable, auto-disposing -observer that acts as a lambda observer (pass-through) unless the underlying scope `Maybe` emits. -Both scope end and upstream termination result in immediate disposable of both the underlying scope -subscription and upstream disposable. - -### Support/Extensions - -`Flowable`, `Observable`, `Maybe`, `Single`, and `Completable` are all supported. Implementation is solely -based on their `Observer` types, so conceivably any type that uses those for subscription should work. - #### AutoDisposePlugins Modeled after RxJava's plugins, this allows you to customize the behavior of AutoDispose. +##### OutsideLifecycleHandler + +When a lifecycle has not started or has already ended, `AutoDispose` will send an error event with an + `OutsideLifecycleException` to downstream consumers. If you want to customize this behavior, you can use + `AutoDisposePlugins#setOutsideLifecycleHandler` to intercept these exceptions and rethrow something + else or nothing at all. + Example ```java AutoDisposePlugins.setOutsideLifecycleHandler(t -> { @@ -126,6 +112,36 @@ AutoDisposePlugins.setOutsideLifecycleHandler(t -> { A good use case of this is, say, just silently disposing/logging observers outside of lifecycle exceptions in production but crashing on debug. +##### FillInOutsideLifecycleExceptionStacktraces + +If you have your own handling of exceptions in lifecycle boundary events, you can optionally set +`AutoDisposePlugins#setFillInOutsideLifecycleExceptionStacktraces` to `false`. This will result in +AutoDispose `not` filling in stacktraces for exceptions, for a potential minor performance boost. + +### Behavior + +Under the hood, AutoDispose decorates RxJava's real observer with a custom *AutoDisposing* observer. +This custom observer leverages the scope to create a disposable, auto-disposing observer that acts +as a lambda observer (pass-through) unless the underlying scope `Maybe` emits `onSuccess`. Both +scope emission and upstream termination result in immediate disposable of both the underlying scope +subscription and upstream disposable. + +In the event that the scope `Maybe` emits `onComplete`, the execution is unbound (as if autodispose +was never enabled on the observation). + +These custom `AutoDisposing` observers are considered public read-only API, and can be found under the +`observers` package. They also support retrieval of the underlying observer via `delegateObserver()` +methods. Read-only API means that the public signatures will follow semantic versioning, but we may +add new methods in the future (which would break compilation if you make custom implementations!). + +To read this information, you can use RxJava's `onSubscribe` hooks in `RxJavaPlugins` to watch for +instances of these observers. + +### Support/Extensions + +`Flowable`, `Observable`, `Maybe`, `Single`, and `Completable` are all supported. Implementation is solely +based on their `Observer` types, so conceivably any type that uses those for subscription should work. + #### Extensions There are also a number of extension artifacts available, detailed below. @@ -187,7 +203,6 @@ Another caveat we often ran into (and later aggressively linted against) was tha ordering implications, and needed to be as close to the `subscribe()` call as possible to properly wrap upstream. If binding to views, there were also threading requirements on the observable chain in order to work properly. - At the end of the day, we wanted true disposal/unsubscription-based behavior, but with RxLifecycle-esque semantics around scope resolution. RxJava 2's `Observer` interfaces provide the perfect mechanism for this via their `onSubscribe()` callbacks. The result is de-risked `Single`/`Completable` usage, no ordering diff --git a/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingCompletableObserver.java b/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingCompletableObserver.java index 7dd24112b..0fa1a3260 100644 --- a/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingCompletableObserver.java +++ b/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingCompletableObserver.java @@ -17,7 +17,6 @@ package com.uber.autodispose.observers; import io.reactivex.CompletableObserver; -import io.reactivex.annotations.Experimental; import io.reactivex.disposables.Disposable; /** @@ -28,8 +27,7 @@ public interface AutoDisposingCompletableObserver extends CompletableObserver, D /** * @return The delegate {@link CompletableObserver} that is used under the hood for introspection - * purposes. This will be updated once LambdaIntrospection is out of @Experimental in RxJava. + * purposes. */ - @Experimental CompletableObserver delegateObserver(); } diff --git a/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingMaybeObserver.java b/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingMaybeObserver.java index d4db418ec..65742729a 100644 --- a/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingMaybeObserver.java +++ b/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingMaybeObserver.java @@ -17,7 +17,6 @@ package com.uber.autodispose.observers; import io.reactivex.MaybeObserver; -import io.reactivex.annotations.Experimental; import io.reactivex.disposables.Disposable; /** @@ -27,9 +26,8 @@ public interface AutoDisposingMaybeObserver extends MaybeObserver, Disposable { /** - * @return The delegate {@link MayberObserver} that is used under the hood for introspection - * purposes. This will be updated once LambdaIntrospection is out of @Experimental in RxJava. + * @return The delegate {@link MaybeObserver} that is used under the hood for introspection + * purposes. */ - @Experimental MaybeObserver delegateObserver(); } diff --git a/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingObserver.java b/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingObserver.java index 1314bfa2a..7f98c7443 100644 --- a/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingObserver.java +++ b/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingObserver.java @@ -17,7 +17,6 @@ package com.uber.autodispose.observers; import io.reactivex.Observer; -import io.reactivex.annotations.Experimental; import io.reactivex.disposables.Disposable; /** @@ -28,8 +27,6 @@ public interface AutoDisposingObserver extends Observer, Disposable { /** * @return The delegate {@link Observer} that is used under the hood for introspection purposes. - * This will be updated once LambdaIntrospection is out of @Experimental in RxJava. */ - @Experimental Observer delegateObserver(); } diff --git a/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingSingleObserver.java b/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingSingleObserver.java index d013acb70..d5dabbd47 100644 --- a/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingSingleObserver.java +++ b/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingSingleObserver.java @@ -17,7 +17,6 @@ package com.uber.autodispose.observers; import io.reactivex.SingleObserver; -import io.reactivex.annotations.Experimental; import io.reactivex.disposables.Disposable; /** @@ -28,8 +27,7 @@ public interface AutoDisposingSingleObserver extends SingleObserver, Dispo /** * @return The delegate {@link SingleObserver} that is used under the hood for introspection - * purposes. This will be updated once LambdaIntrospection is out of @Experimental in RxJava. + * purposes. */ - @Experimental SingleObserver delegateObserver(); } diff --git a/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingSubscriber.java b/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingSubscriber.java index 2740dc1ff..ddbe754c7 100644 --- a/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingSubscriber.java +++ b/autodispose/src/main/java/com/uber/autodispose/observers/AutoDisposingSubscriber.java @@ -17,7 +17,6 @@ package com.uber.autodispose.observers; import io.reactivex.FlowableSubscriber; -import io.reactivex.annotations.Experimental; import io.reactivex.disposables.Disposable; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; @@ -31,8 +30,7 @@ public interface AutoDisposingSubscriber /** * @return The delegate {@link Subscriber} that is used under the hood for introspection - * purposes. This will be updated once LambdaIntrospection is out of @Experimental in RxJava. + * purposes. */ - @Experimental Subscriber delegateSubscriber(); } diff --git a/build.gradle b/build.gradle index ce8b87a2d..bd36205cb 100755 --- a/build.gradle +++ b/build.gradle @@ -14,6 +14,19 @@ * limitations under the License. */ +subprojects { + buildscript { + repositories { + jcenter() + } + } + + repositories { + jcenter() + google() + } +} + task wrapper(type: Wrapper) { gradleVersion = '4.3.1' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" diff --git a/gradle/checkstyle.gradle b/gradle/checkstyle.gradle index 86dd9dd58..abd1b2c59 100644 --- a/gradle/checkstyle.gradle +++ b/gradle/checkstyle.gradle @@ -15,19 +15,6 @@ */ subprojects { - buildscript { - repositories { - jcenter() - } - } - - repositories { - jcenter() - maven { - url 'https://maven.google.com' - } - } - apply plugin: 'checkstyle' afterEvaluate { @@ -43,7 +30,7 @@ subprojects { exclude '**/R.java' exclude '**/BuildConfig.java' reports { - xml.destination "$project.buildDir/reports/checkstyle/main.xml" + xml.destination new File("$project.buildDir/reports/checkstyle/main.xml") } classpath = files() configFile = rootProject.file('checkstyle.xml') @@ -58,7 +45,7 @@ subprojects { exclude '**/R.java' exclude '**/BuildConfig.java' reports { - xml.destination "$project.buildDir/reports/checkstyle/test.xml" + xml.destination new File("$project.buildDir/reports/checkstyle/test.xml") } classpath = files() configFile = rootProject.file('checkstyle.xml')