-
Notifications
You must be signed in to change notification settings - Fork 226
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RxLifecycle interop module #118
Changes from 15 commits
d078017
159205a
25f3868
19a0445
12840a9
335f22b
5f2be30
11f6174
ce14957
c38dd9c
f33e1c7
06be7fb
51d7989
7182d54
e463be6
7f3e1a8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* | ||
* Copyright (C) 2017. Uber Technologies | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
buildscript { | ||
repositories { | ||
jcenter() | ||
maven { url deps.build.repositories.plugins } | ||
} | ||
dependencies { | ||
classpath deps.build.gradlePlugins.apt | ||
classpath deps.build.gradlePlugins.errorProne | ||
} | ||
} | ||
|
||
apply plugin: 'java-library' | ||
apply plugin: 'net.ltgt.apt' | ||
apply plugin: 'net.ltgt.errorprone' | ||
|
||
sourceCompatibility = "1.7" | ||
targetCompatibility = "1.7" | ||
|
||
test { | ||
testLogging.showStandardStreams = true | ||
} | ||
|
||
dependencies { | ||
apt deps.build.nullAway | ||
testApt deps.build.nullAway | ||
|
||
compile project(':autodispose') | ||
compile deps.misc.rxlifecycle | ||
compileOnly deps.misc.errorProneAnnotations | ||
compileOnly deps.misc.javaxExtras | ||
|
||
errorprone deps.build.checkerFramework | ||
errorprone deps.build.errorProne | ||
|
||
testCompile project(':test-utils') | ||
} | ||
|
||
tasks.withType(JavaCompile) { | ||
options.compilerArgs += ["-Xep:NullAway:ERROR", "-XepOpt:NullAway:AnnotatedPackages=com.uber"] | ||
} | ||
|
||
apply from: rootProject.file('gradle/gradle-mvn-push.gradle') |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# | ||
# Copyright (C) 2017. Uber Technologies | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
|
||
POM_NAME=AutoDispose (RxLifecycle Interop) | ||
POM_ARTIFACT_ID=autodispose-rxlifecycle | ||
POM_PACKAGING=jar |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/* | ||
* Copyright (c) 2017. Uber Technologies | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.ubercab.autodispose.rxlifecycle; | ||
|
||
import com.trello.rxlifecycle2.LifecycleProvider; | ||
import com.trello.rxlifecycle2.OutsideLifecycleException; | ||
import com.uber.autodispose.AutoDispose.ScopeHandler; | ||
import com.uber.autodispose.LifecycleEndedException; | ||
import com.uber.autodispose.ScopeProvider; | ||
import io.reactivex.Maybe; | ||
|
||
/** | ||
* Interop for RxLifecycle. It provides static utility methods to convert {@link | ||
* LifecycleProvider} to {@link ScopeProvider}. | ||
* | ||
* <p>There are several static utility converter | ||
* methods such as {@link #from(LifecycleProvider)} for {@link | ||
* LifecycleProvider#bindToLifecycle()} and {@link #from(LifecycleProvider, Object)} for | ||
* {@link LifecycleProvider#bindUntilEvent(Object)}. | ||
* <p> | ||
* | ||
* <em>Note:</em> RxLifecycle treats the {@link OutsideLifecycleException} | ||
* as normal terminal event. There is no mapping to {@link LifecycleEndedException} and in such | ||
* cases the stream is normally disposed. | ||
*/ | ||
public final class RxLifecycleInterop { | ||
|
||
private RxLifecycleInterop() { | ||
throw new AssertionError("No Instances"); | ||
} | ||
|
||
private static final Object DEFAULT_THROWAWAY_OBJECT = new Object(); | ||
|
||
/** | ||
* Converter for transforming {@link LifecycleProvider} to {@link ScopeProvider}. | ||
* It disposes the source when the next reasonable event occurs. | ||
* <p> | ||
* Example usage: | ||
* <pre><code> | ||
* Observable.just(1) | ||
* .to(RxLifecycleInterop.from(lifecycleProvider)) | ||
* .subscribe(...) | ||
* </code></pre> | ||
* | ||
* @param <E> the lifecycle event. | ||
* @param provider the {@link LifecycleProvider} for RxLifecycle. | ||
* @return a {@link ScopeHandler} to create AutoDisposing transformation | ||
*/ | ||
public static <E> ScopeProvider from(final LifecycleProvider<E> provider) { | ||
return new ScopeProvider() { | ||
@Override public Maybe<?> requestScope() { | ||
return provider.lifecycle() | ||
.compose(provider.bindToLifecycle()) | ||
.ignoreElements() | ||
.toMaybe() | ||
.defaultIfEmpty(DEFAULT_THROWAWAY_OBJECT); | ||
} | ||
}; | ||
} | ||
|
||
/** | ||
* Converter for transforming {@link LifecycleProvider} to {@link ScopeProvider}. | ||
* It disposes the source when a specific event occurs. | ||
* <p> | ||
* Example usage: | ||
* <pre><code> | ||
* Observable.just(1) | ||
* .to(RxLifecycleInterop.from(lifecycleProvider, event)) | ||
* .subscribe(...) | ||
* </code></pre> | ||
* | ||
* @param <E> the lifecycle event. | ||
* @param provider the {@link LifecycleProvider} for RxLifecycle. | ||
* @param event the event at which the source is disposed. | ||
* @return a {@link ScopeHandler} to create AutoDisposing transformation | ||
*/ | ||
public static <E> ScopeProvider from(final LifecycleProvider<E> provider, final E event) { | ||
return new ScopeProvider() { | ||
@Override public Maybe<?> requestScope() { | ||
return provider.lifecycle() | ||
.compose(provider.bindUntilEvent(event)) | ||
.ignoreElements() | ||
.toMaybe() | ||
.defaultIfEmpty(DEFAULT_THROWAWAY_OBJECT); | ||
} | ||
}; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* | ||
* Copyright (c) 2017. Uber Technologies | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
/** | ||
* Interop for RxLifecycle. It could understand RxLifecycle's | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can phrase this better, doesn't have to be too wordy. Let's do
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed - 7f3e1a8 |
||
* LifecycleProvider mechanics, which in turn lend support to different | ||
* components such as RxActivity. It does so by providing converters to retrieve ScopeProvider. | ||
*/ | ||
@com.uber.javaxextras.FieldsMethodsAndParametersAreNonNullByDefault | ||
package com.ubercab.autodispose.rxlifecycle; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
/* | ||
* Copyright (c) 2017. Uber Technologies | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.ubercab.autodispose.rxlifecycle; | ||
|
||
import com.uber.autodispose.AutoDispose; | ||
import com.uber.autodispose.test.RecordingObserver; | ||
import io.reactivex.disposables.Disposable; | ||
import io.reactivex.observers.TestObserver; | ||
import io.reactivex.subjects.PublishSubject; | ||
import org.junit.Test; | ||
|
||
import static com.google.common.truth.Truth.assertThat; | ||
|
||
public class RxLifecycleInteropTest { | ||
|
||
private static final RecordingObserver.Logger LOGGER = new RecordingObserver.Logger() { | ||
@Override public void log(String message) { | ||
System.out.println(RxLifecycleInteropTest.class.getSimpleName() + ": " + message); | ||
} | ||
}; | ||
|
||
private TestLifecycleProvider lifecycleProvider = new TestLifecycleProvider(); | ||
|
||
@Test | ||
public void bindLifecycle_normalTermination_completeTheStream() { | ||
lifecycleProvider.emitCreate(); | ||
TestObserver<Integer> o = new TestObserver<>(); | ||
PublishSubject<Integer> source = PublishSubject.create(); | ||
Disposable d = source.to(AutoDispose.with( | ||
RxLifecycleInterop.from(lifecycleProvider)).<Integer>forObservable()) | ||
.subscribeWith(o); | ||
o.assertSubscribed(); | ||
|
||
assertThat(source.hasObservers()).isTrue(); | ||
|
||
source.onNext(1); | ||
o.assertValue(1); | ||
|
||
source.onNext(2); | ||
source.onComplete(); | ||
o.assertValues(1, 2); | ||
o.assertComplete(); | ||
assertThat(d.isDisposed()).isFalse(); // Because it completed normally, was not disposed. | ||
assertThat(source.hasObservers()).isFalse(); | ||
} | ||
|
||
@Test | ||
public void bindLifecycle_normalTermination_unsubscribe() { | ||
lifecycleProvider.emitCreate(); | ||
RecordingObserver<Integer> o = new RecordingObserver<>(LOGGER); | ||
PublishSubject<Integer> source = PublishSubject.create(); | ||
source.to(AutoDispose.with( | ||
RxLifecycleInterop.from(lifecycleProvider)).<Integer>forObservable()) | ||
.subscribe(o); | ||
o.takeSubscribe(); | ||
|
||
assertThat(source.hasObservers()).isTrue(); | ||
|
||
source.onNext(1); | ||
assertThat(o.takeNext()).isEqualTo(1); | ||
|
||
lifecycleProvider.emitDestroy(); | ||
source.onNext(2); | ||
o.assertNoMoreEvents(); | ||
assertThat(source.hasObservers()).isFalse(); | ||
} | ||
|
||
@Test | ||
public void bindLifecycle_outsideLifecycleBound_unsubscribe() { | ||
lifecycleProvider.emitCreate(); | ||
RecordingObserver<Integer> o = new RecordingObserver<>(LOGGER); | ||
PublishSubject<Integer> source = PublishSubject.create(); | ||
lifecycleProvider.emitDestroy(); | ||
source | ||
.to(AutoDispose.with( | ||
RxLifecycleInterop.from(lifecycleProvider)).<Integer>forObservable()) | ||
.subscribe(o); | ||
|
||
o.takeSubscribe(); | ||
|
||
source.onNext(2); | ||
o.assertNoMoreEvents(); | ||
assertThat( | ||
source.hasObservers()).isFalse(); // Because RxLifecycle | ||
// treats OutsideLifecycleException as terminal event. | ||
} | ||
|
||
@Test | ||
public void bindUntilEvent_normalTermination_completeTheStream() { | ||
lifecycleProvider.emitCreate(); | ||
TestObserver<Integer> o = new TestObserver<>(); | ||
PublishSubject<Integer> source = PublishSubject.create(); | ||
Disposable d = source.to(AutoDispose.with(RxLifecycleInterop.from( | ||
lifecycleProvider, | ||
TestLifecycleProvider.Event.DESTROY)).<Integer>forObservable()) | ||
.subscribeWith(o); | ||
o.assertSubscribed(); | ||
|
||
assertThat(source.hasObservers()).isTrue(); | ||
|
||
source.onNext(1); | ||
o.assertValue(1); | ||
|
||
source.onNext(2); | ||
source.onComplete(); | ||
o.assertValues(1, 2); | ||
o.assertComplete(); | ||
assertThat(d.isDisposed()).isFalse(); // Because it completed normally, was not disposed. | ||
assertThat(source.hasObservers()).isFalse(); | ||
} | ||
|
||
@Test | ||
public void bindUntilEvent_interruptedTermination_unsubscribe() { | ||
lifecycleProvider.emitCreate(); | ||
RecordingObserver<Integer> o = new RecordingObserver<>(LOGGER); | ||
PublishSubject<Integer> source = PublishSubject.create(); | ||
source.to(AutoDispose.with(RxLifecycleInterop.from(lifecycleProvider, | ||
TestLifecycleProvider.Event.DESTROY)).<Integer>forObservable()) | ||
.subscribe(o); | ||
o.takeSubscribe(); | ||
|
||
assertThat(source.hasObservers()).isTrue(); | ||
|
||
source.onNext(1); | ||
assertThat(o.takeNext()).isEqualTo(1); | ||
|
||
lifecycleProvider.emitDestroy(); | ||
source.onNext(2); | ||
o.assertNoMoreEvents(); | ||
assertThat(source.hasObservers()).isFalse(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missed this in my earlier comments, but these two methods should each have docs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in c2e63ff