From 868597ece5aa1aa446184db8bad68a03d9a05842 Mon Sep 17 00:00:00 2001 From: StefMa Date: Wed, 21 Dec 2016 12:55:18 +0100 Subject: [PATCH 1/7] Create new rx2 module --- rx2/.gitignore | 1 + rx2/build.gradle | 55 ++++++++++++++++++++++++++++++++ rx2/src/main/AndroidManifest.xml | 5 +++ settings.gradle | 2 +- 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 rx2/.gitignore create mode 100644 rx2/build.gradle create mode 100644 rx2/src/main/AndroidManifest.xml diff --git a/rx2/.gitignore b/rx2/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/rx2/.gitignore @@ -0,0 +1 @@ +/build diff --git a/rx2/build.gradle b/rx2/build.gradle new file mode 100644 index 00000000..efe6426a --- /dev/null +++ b/rx2/build.gradle @@ -0,0 +1,55 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath "com.novoda:bintray-release:$bintrayVersion" + } +} + +apply plugin: 'com.android.library' +apply plugin: 'bintray-release' +apply plugin: 'jacoco-android' + +android { + compileSdkVersion COMPILE_SDK_VERSION + buildToolsVersion BUILD_TOOLS_VERSION + + defaultConfig { + minSdkVersion MIN_SDK_VERSION + targetSdkVersion TARGET_SDK_VERSION + versionCode VERSION_CODE + versionName VERSION_NAME + } + buildTypes { + release { + minifyEnabled false + } + debug { + // output coverage with ./gradlew clean build createDebugCoverageReport + testCoverageEnabled true + } + } + lintOptions { + abortOnError false + } +} + +dependencies { + compile project(':thirtyinch') + compile 'io.reactivex.rxjava2:rxjava:2.0.3' + provided "com.android.support:support-annotations:$supportLibraryVersion" + + testCompile "junit:junit:$junitVersion" + testCompile "org.mockito:mockito-core:$mockitoVersion" +} + +publish { + userOrg = 'passsy' + groupId = 'net.grandcentrix.thirtyinch' + artifactId = 'thirtyinch-rx' + uploadName = 'ThirtyInch' + publishVersion = VERSION_NAME + //description = '' + website = 'https://github.com/grandcentrix/ThirtyInch' +} \ No newline at end of file diff --git a/rx2/src/main/AndroidManifest.xml b/rx2/src/main/AndroidManifest.xml new file mode 100644 index 00000000..7f593b78 --- /dev/null +++ b/rx2/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/settings.gradle b/settings.gradle index 87e0b83e..8588ceb2 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':thirtyinch', ':plugin', ':sample', ':rx', ':test', ':plugin-test' +include ':thirtyinch', ':plugin', ':sample', ':rx', ':test', ':plugin-test', ':rx2' From fb99069dcc49566da0414c579c50dc0d305719a9 Mon Sep 17 00:00:00 2001 From: StefMa Date: Thu, 22 Dec 2016 12:24:53 +0100 Subject: [PATCH 2/7] Create RxTiPresenterDisposableHandler --- .../rx2/RxTiPresenterDisposableHandler.java | 104 ++++++++++++ .../RxTiPresenterDisposableHandlerTest.java | 152 ++++++++++++++++++ .../thirtyinch/rx2/TiMockPresenter.java | 56 +++++++ 3 files changed, 312 insertions(+) create mode 100644 rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandler.java create mode 100644 rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandlerTest.java create mode 100644 rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/TiMockPresenter.java diff --git a/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandler.java b/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandler.java new file mode 100644 index 00000000..f7860f73 --- /dev/null +++ b/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandler.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2016 grandcentrix GmbH + * 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 net.grandcentrix.thirtyinch.rx2; + +import net.grandcentrix.thirtyinch.TiLifecycleObserver; +import net.grandcentrix.thirtyinch.TiPresenter; +import net.grandcentrix.thirtyinch.TiView; + +import android.support.annotation.NonNull; + +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.disposables.Disposable; + +public class RxTiPresenterDisposableHandler { + + private CompositeDisposable mPresenterDisposables = new CompositeDisposable(); + + private CompositeDisposable mUiDisposables; + + public RxTiPresenterDisposableHandler(final TiPresenter presenter) { + presenter.addLifecycleObserver(new TiLifecycleObserver() { + @Override + public void onChange(final TiPresenter.State state, + final boolean beforeLifecycleEvent) { + if (state == TiPresenter.State.VIEW_DETACHED && beforeLifecycleEvent) { + // dispose all UI disposable created in wakeUp() and added + // via manageViewDisposable(Disposable...) + if (mUiDisposables != null) { + mUiDisposables.dispose(); + } + // there is no reuse possible. recreation works fine + mUiDisposables = new CompositeDisposable(); + } + + if (state == TiPresenter.State.DESTROYED && beforeLifecycleEvent) { + mPresenterDisposables.dispose(); + mPresenterDisposables = null; + } + } + }); + + } + + /** + * Add your disposables here and they will automatically disposed when + * {@link TiPresenter#destroy()} gets called + * + * @throws IllegalStateException when the presenter has reached {@link net.grandcentrix.thirtyinch.TiPresenter.State#DESTROYED} + */ + public void manageDisposable(@NonNull final Disposable... disposables) { + if (mPresenterDisposables == null) { + throw new IllegalStateException("disposable handling doesn't work" + + " when the presenter has reached the DESTROYED state"); + } + + addDisposables(mPresenterDisposables, disposables); + } + + /** + * Add your disposables for View events to this method to get them automatically cleaned up + * in {@link TiPresenter#detachView()}. typically call this in {@link + * TiPresenter#attachView(TiView)} where you dispose to the UI events. + * + * @throws IllegalStateException when no view is attached + */ + public void manageViewDisposable(@NonNull final Disposable... disposables) { + if (mUiDisposables == null) { + throw new IllegalStateException("view disposable can't be handled" + + " when there is no view"); + } + + addDisposables(mUiDisposables, disposables); + } + + /** + * Adds all disposables to the given compositeDisposable if not already disposed + */ + private static void addDisposables(final CompositeDisposable compositeDisposable, + final Disposable... disposables) { + //noinspection ForLoopReplaceableByForEach + for (int i = 0; i < disposables.length; i++) { + final Disposable disposable = disposables[i]; + if (disposable.isDisposed()) { + continue; + } + + compositeDisposable.add(disposable); + } + } + +} diff --git a/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandlerTest.java b/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandlerTest.java new file mode 100644 index 00000000..5403c2fa --- /dev/null +++ b/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandlerTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2016 grandcentrix GmbH + * 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 net.grandcentrix.thirtyinch.rx2; + +import net.grandcentrix.thirtyinch.TiView; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import io.reactivex.observers.TestObserver; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; + +@RunWith(JUnit4.class) +public class RxTiPresenterDisposableHandlerTest { + + private RxTiPresenterDisposableHandler mDisposableHandler; + + private TiMockPresenter mPresenter; + + private TiView mView; + + @Before + public void setUp() throws Exception { + mPresenter = new TiMockPresenter(); + mDisposableHandler = new RxTiPresenterDisposableHandler(mPresenter); + mView = mock(TiView.class); + } + + @Test + public void testManageDisposable_AfterDestroy_ShouldThrowIllegalState() throws Exception { + mPresenter.create(); + mPresenter.destroy(); + final TestObserver testObserver = new TestObserver<>(); + + try { + mDisposableHandler.manageDisposable(testObserver); + fail("no exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage(), containsString("DESTROYED")); + } + } + + @Test + public void testManageDisposable_WithAlreadyDisposedDisposable_ShouldDoNothing() + throws Exception { + final TestObserver testObserver = new TestObserver<>(); + testObserver.dispose(); + assertThat(testObserver.isDisposed(), is(true)); + + mDisposableHandler.manageDisposable(testObserver); + + assertThat(testObserver.isDisposed(), is(true)); + } + + @Test + public void testManageDisposable_WithDestroy_ShouldDispose() throws Exception { + mPresenter.create(); + final TestObserver testObserver = new TestObserver<>(); + + mDisposableHandler.manageDisposable(testObserver); + assertThat(testObserver.isDisposed(), is(false)); + + mPresenter.destroy(); + assertThat(testObserver.isDisposed(), is(true)); + } + + @Test + public void testManageVieDisposable_WithDetachSingleDispose_ShouldDispose() + throws Exception { + mPresenter.create(); + mPresenter.attachView(mView); + final TestObserver testObserver = new TestObserver<>(); + + mDisposableHandler.manageViewDisposable(testObserver); + assertThat(testObserver.isDisposed(), is(false)); + + mPresenter.detachView(); + assertThat(testObserver.isDisposed(), is(true)); + } + + @Test + public void testManageViewDisposable_DetachBeforeAttach_ShouldThrowAssertError() + throws Exception { + mPresenter.create(); + final TestObserver testObserver = new TestObserver<>(); + + mDisposableHandler.manageViewDisposable(testObserver); + mPresenter.detachView(); + + // Think about that. + // Maybe this will never happen. But when! Then we have to dispose all the view disposable. + // Same in rx module + assertThat(testObserver.isDisposed(), is(false)); + } + + @Test + public void testManageViewDisposeable_WithOneAlreadyDisposed_ShouldNotAddToDisposable() + throws Exception { + mPresenter.create(); + mPresenter.attachView(mView); + final TestObserver firstTestObserver = new TestObserver<>(); + final TestObserver secondTestObserver = new TestObserver<>(); + secondTestObserver.dispose(); + + mDisposableHandler.manageViewDisposable(firstTestObserver, secondTestObserver); + + assertThat(firstTestObserver.isDisposed(), is(false)); + assertThat(secondTestObserver.isDisposed(), is(true)); + } + + + @Test + public void testManagerViewDisposable_WithDetach_ShouldDispose() throws Exception { + mPresenter.create(); + mPresenter.attachView(mView); + final TestObserver firstTestObserver = new TestObserver<>(); + final TestObserver secondTestObserver = new TestObserver<>(); + final TestObserver thirdTestObserver = new TestObserver<>(); + + mDisposableHandler + .manageViewDisposable(firstTestObserver, secondTestObserver, thirdTestObserver); + assertThat(firstTestObserver.isDisposed(), equalTo(false)); + assertThat(secondTestObserver.isDisposed(), equalTo(false)); + assertThat(thirdTestObserver.isDisposed(), equalTo(false)); + + mPresenter.detachView(); + assertThat(firstTestObserver.isDisposed(), equalTo(true)); + assertThat(secondTestObserver.isDisposed(), equalTo(true)); + assertThat(thirdTestObserver.isDisposed(), equalTo(true)); + } +} \ No newline at end of file diff --git a/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/TiMockPresenter.java b/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/TiMockPresenter.java new file mode 100644 index 00000000..8550c30f --- /dev/null +++ b/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/TiMockPresenter.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 grandcentrix GmbH + * 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 net.grandcentrix.thirtyinch.rx2; + +import net.grandcentrix.thirtyinch.TiPresenter; +import net.grandcentrix.thirtyinch.TiView; + +import android.support.annotation.NonNull; + +class TiMockPresenter extends TiPresenter { + + protected int onAttachCalled = 0; + + protected int onCreateCalled = 0; + + protected int onDestroyCalled = 0; + + protected int onDetachCalled = 0; + + @Override + protected void onAttachView(@NonNull final TiView view) { + super.onAttachView(view); + onAttachCalled++; + } + + @Override + protected void onCreate() { + super.onCreate(); + onCreateCalled++; + } + + @Override + protected void onDestroy() { + super.onDestroy(); + onDestroyCalled++; + } + + @Override + protected void onDetachView() { + super.onDetachView(); + onDetachCalled++; + } +} \ No newline at end of file From 57264bdcf69aced7013a558c66e9fd8d60b6b4c2 Mon Sep 17 00:00:00 2001 From: StefMa Date: Wed, 4 Jan 2017 13:39:39 +0100 Subject: [PATCH 3/7] Create RxTiPresenterUtils#isViewReady --- .../thirtyinch/rx2/RxTiPresenterUtils.java | 73 +++++++++++++++++++ .../rx2/RxTiPresenterUtilsTest.java | 62 ++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterUtils.java create mode 100644 rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterUtilsTest.java diff --git a/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterUtils.java b/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterUtils.java new file mode 100644 index 00000000..92f76219 --- /dev/null +++ b/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterUtils.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2016 grandcentrix GmbH + * 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 net.grandcentrix.thirtyinch.rx2; + +import net.grandcentrix.thirtyinch.Removable; +import net.grandcentrix.thirtyinch.TiLifecycleObserver; +import net.grandcentrix.thirtyinch.TiPresenter; +import net.grandcentrix.thirtyinch.TiView; + +import io.reactivex.Observable; +import io.reactivex.ObservableEmitter; +import io.reactivex.ObservableOnSubscribe; +import io.reactivex.disposables.Disposable; + +public class RxTiPresenterUtils { + + /** + * Observable of the view state. The View is ready to receive calls after calling {@link + * TiPresenter#attachView(TiView)} and before calling {@link TiPresenter#detachView()}. + */ + public static Observable isViewReady(final TiPresenter presenter) { + return Observable.create( + new ObservableOnSubscribe() { + @Override + public void subscribe(final ObservableEmitter emitter) + throws Exception { + if (!emitter.isDisposed()) { + emitter.onNext(presenter.getState() + == TiPresenter.State.VIEW_ATTACHED); + } + + final Removable removable = presenter + .addLifecycleObserver(new TiLifecycleObserver() { + @Override + public void onChange(final TiPresenter.State state, + final boolean beforeLifecycleEvent) { + if (!emitter.isDisposed()) { + emitter.onNext(state == + TiPresenter.State.VIEW_ATTACHED); + } + } + }); + + emitter.setDisposable(new Disposable() { + @Override + public void dispose() { + removable.remove(); + } + + @Override + public boolean isDisposed() { + return removable.isRemoved(); + } + }); + } + }) + .distinctUntilChanged(); + } + +} diff --git a/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterUtilsTest.java b/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterUtilsTest.java new file mode 100644 index 00000000..c69d9476 --- /dev/null +++ b/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterUtilsTest.java @@ -0,0 +1,62 @@ +package net.grandcentrix.thirtyinch.rx2; + +import net.grandcentrix.thirtyinch.TiView; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import io.reactivex.observers.TestObserver; + +import static org.mockito.Mockito.mock; + +public class RxTiPresenterUtilsTest { + + private TiMockPresenter mPresenter; + + private TiView mView; + + @Before + public void setUp() throws Exception { + mView = mock(TiView.class); + mPresenter = new TiMockPresenter(); + } + + @After + public void tearDown() throws Exception { + mPresenter = null; + mView = null; + } + + @Test + public void testIsViewReady_AttachView_ShouldCallValueFalseTrue() throws Exception { + mPresenter.create(); + + final TestObserver test = RxTiPresenterUtils.isViewReady(mPresenter).test(); + + mPresenter.attachView(mView); + test.assertValues(false, true); + } + + @Test + public void testIsViewReady_BeforeAttachView_ShouldCallValueFalse() throws Exception { + mPresenter.create(); + + final TestObserver test = RxTiPresenterUtils.isViewReady(mPresenter).test(); + + test.assertValue(false); + } + + @Test + public void testIsViewReady_DisposeBeforeAttachView_ShouldRemoveCallback() throws Exception { + mPresenter.create(); + + final TestObserver test = RxTiPresenterUtils.isViewReady(mPresenter).test(); + + test.assertValue(false); + test.dispose(); + test.isDisposed(); + mPresenter.attachView(mView); + test.assertValue(false); + } +} \ No newline at end of file From 12e301e4a7dc6cabdb499c87b3bab6e1e2e54ead Mon Sep 17 00:00:00 2001 From: Pascal Welsch Date: Fri, 6 Jan 2017 17:03:00 +0100 Subject: [PATCH 4/7] Remove unused TiMockPresenter --- .../RxTiPresenterDisposableHandlerTest.java | 6 +- .../thirtyinch/rx2/TiMockPresenter.java | 56 ------------------- 2 files changed, 4 insertions(+), 58 deletions(-) delete mode 100644 rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/TiMockPresenter.java diff --git a/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandlerTest.java b/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandlerTest.java index 5403c2fa..47cb702f 100644 --- a/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandlerTest.java +++ b/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandlerTest.java @@ -15,6 +15,7 @@ package net.grandcentrix.thirtyinch.rx2; +import net.grandcentrix.thirtyinch.TiPresenter; import net.grandcentrix.thirtyinch.TiView; import org.junit.Before; @@ -36,13 +37,14 @@ public class RxTiPresenterDisposableHandlerTest { private RxTiPresenterDisposableHandler mDisposableHandler; - private TiMockPresenter mPresenter; + private TiPresenter mPresenter; private TiView mView; @Before public void setUp() throws Exception { - mPresenter = new TiMockPresenter(); + mPresenter = new TiPresenter() { + }; mDisposableHandler = new RxTiPresenterDisposableHandler(mPresenter); mView = mock(TiView.class); } diff --git a/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/TiMockPresenter.java b/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/TiMockPresenter.java deleted file mode 100644 index 8550c30f..00000000 --- a/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/TiMockPresenter.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2016 grandcentrix GmbH - * 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 net.grandcentrix.thirtyinch.rx2; - -import net.grandcentrix.thirtyinch.TiPresenter; -import net.grandcentrix.thirtyinch.TiView; - -import android.support.annotation.NonNull; - -class TiMockPresenter extends TiPresenter { - - protected int onAttachCalled = 0; - - protected int onCreateCalled = 0; - - protected int onDestroyCalled = 0; - - protected int onDetachCalled = 0; - - @Override - protected void onAttachView(@NonNull final TiView view) { - super.onAttachView(view); - onAttachCalled++; - } - - @Override - protected void onCreate() { - super.onCreate(); - onCreateCalled++; - } - - @Override - protected void onDestroy() { - super.onDestroy(); - onDestroyCalled++; - } - - @Override - protected void onDetachView() { - super.onDetachView(); - onDetachCalled++; - } -} \ No newline at end of file From 1773124a9413d242a273a448e44a77e86c122175 Mon Sep 17 00:00:00 2001 From: Pascal Welsch Date: Mon, 9 Jan 2017 15:46:23 +0100 Subject: [PATCH 5/7] Remove TiMockPresenter from tests --- .../grandcentrix/thirtyinch/rx2/RxTiPresenterUtilsTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterUtilsTest.java b/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterUtilsTest.java index c69d9476..85b8b01f 100644 --- a/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterUtilsTest.java +++ b/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterUtilsTest.java @@ -1,5 +1,6 @@ package net.grandcentrix.thirtyinch.rx2; +import net.grandcentrix.thirtyinch.TiPresenter; import net.grandcentrix.thirtyinch.TiView; import org.junit.After; @@ -12,14 +13,15 @@ public class RxTiPresenterUtilsTest { - private TiMockPresenter mPresenter; + private TiPresenter mPresenter; private TiView mView; @Before public void setUp() throws Exception { mView = mock(TiView.class); - mPresenter = new TiMockPresenter(); + mPresenter = new TiPresenter() { + }; } @After From 69cb50e7ac5410b1529bb5791d1f457da41613ec Mon Sep 17 00:00:00 2001 From: StefMa Date: Tue, 10 Jan 2017 16:46:01 +0100 Subject: [PATCH 6/7] Throw exception when manageViewDisposable gets called without an attached View --- .../rx2/RxTiPresenterDisposableHandler.java | 4 +++- .../rx2/RxTiPresenterDisposableHandlerTest.java | 15 +++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandler.java b/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandler.java index f7860f73..32901a57 100644 --- a/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandler.java +++ b/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandler.java @@ -41,7 +41,9 @@ public void onChange(final TiPresenter.State state, if (mUiDisposables != null) { mUiDisposables.dispose(); } - // there is no reuse possible. recreation works fine + } + + if (state == TiPresenter.State.VIEW_ATTACHED) { mUiDisposables = new CompositeDisposable(); } diff --git a/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandlerTest.java b/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandlerTest.java index 47cb702f..565bcbbd 100644 --- a/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandlerTest.java +++ b/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandlerTest.java @@ -102,18 +102,17 @@ public void testManageVieDisposable_WithDetachSingleDispose_ShouldDispose() } @Test - public void testManageViewDisposable_DetachBeforeAttach_ShouldThrowAssertError() + public void testManageViewDisposable_DetachBeforeAttach_ShouldThrowIllegalStateException() throws Exception { mPresenter.create(); final TestObserver testObserver = new TestObserver<>(); - mDisposableHandler.manageViewDisposable(testObserver); - mPresenter.detachView(); - - // Think about that. - // Maybe this will never happen. But when! Then we have to dispose all the view disposable. - // Same in rx module - assertThat(testObserver.isDisposed(), is(false)); + try { + mDisposableHandler.manageViewDisposable(testObserver); + fail("no exception"); + } catch (Exception e) { + assertThat(e.getMessage(), containsString("when there is no view")); + } } @Test From ef70fe4d25901ac52d3434fbb01e58eeb4b2be0a Mon Sep 17 00:00:00 2001 From: Pascal Welsch Date: Thu, 19 Jan 2017 17:37:54 +0100 Subject: [PATCH 7/7] Null mUiDisposables when moving to detached state --- .../rx2/RxTiPresenterDisposableHandler.java | 5 +++-- .../RxTiPresenterDisposableHandlerTest.java | 20 +++++++++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandler.java b/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandler.java index 32901a57..ec08524b 100644 --- a/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandler.java +++ b/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandler.java @@ -36,14 +36,15 @@ public RxTiPresenterDisposableHandler(final TiPresenter presenter) { public void onChange(final TiPresenter.State state, final boolean beforeLifecycleEvent) { if (state == TiPresenter.State.VIEW_DETACHED && beforeLifecycleEvent) { - // dispose all UI disposable created in wakeUp() and added + // dispose all UI disposable created in onAttachView(TiView) and added // via manageViewDisposable(Disposable...) if (mUiDisposables != null) { mUiDisposables.dispose(); + mUiDisposables = null; } } - if (state == TiPresenter.State.VIEW_ATTACHED) { + if (state == TiPresenter.State.VIEW_ATTACHED && beforeLifecycleEvent) { mUiDisposables = new CompositeDisposable(); } diff --git a/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandlerTest.java b/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandlerTest.java index 565bcbbd..6a6be215 100644 --- a/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandlerTest.java +++ b/rx2/src/test/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterDisposableHandlerTest.java @@ -102,7 +102,24 @@ public void testManageVieDisposable_WithDetachSingleDispose_ShouldDispose() } @Test - public void testManageViewDisposable_DetachBeforeAttach_ShouldThrowIllegalStateException() + public void testManageViewDisposable_manageAfterDetach_ShouldThrowIllegalStateException() + throws Exception { + mPresenter.create(); + mPresenter.attachView(mView); + mPresenter.detachView(); + + final TestObserver testObserver = new TestObserver<>(); + + try { + mDisposableHandler.manageViewDisposable(testObserver); + fail("no exception"); + } catch (Exception e) { + assertThat(e.getMessage(), containsString("when there is no view")); + } + } + + @Test + public void testManageViewDisposable_manageBeforeViewAttached_ShouldThrowIllegalStateException() throws Exception { mPresenter.create(); final TestObserver testObserver = new TestObserver<>(); @@ -130,7 +147,6 @@ public void testManageViewDisposeable_WithOneAlreadyDisposed_ShouldNotAddToDispo assertThat(secondTestObserver.isDisposed(), is(true)); } - @Test public void testManagerViewDisposable_WithDetach_ShouldDispose() throws Exception { mPresenter.create();