diff --git a/plugin/src/main/java/net/grandcentrix/thirtyinch/plugin/TiActivityPlugin.java b/plugin/src/main/java/net/grandcentrix/thirtyinch/plugin/TiActivityPlugin.java
index 0fcad119..215abca1 100644
--- a/plugin/src/main/java/net/grandcentrix/thirtyinch/plugin/TiActivityPlugin.java
+++ b/plugin/src/main/java/net/grandcentrix/thirtyinch/plugin/TiActivityPlugin.java
@@ -29,6 +29,7 @@
import net.grandcentrix.thirtyinch.internal.TiLoggingTagProvider;
import net.grandcentrix.thirtyinch.internal.TiPresenterProvider;
import net.grandcentrix.thirtyinch.internal.TiViewProvider;
+import net.grandcentrix.thirtyinch.internal.UiThreadExecutor;
import net.grandcentrix.thirtyinch.util.AndroidDeveloperOptions;
import net.grandcentrix.thirtyinch.util.AnnotationUtil;
@@ -39,6 +40,7 @@
import android.support.annotation.Nullable;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* Binds a {@link TiPresenter} to an {@link Activity}
@@ -57,6 +59,8 @@ public class TiActivityPlugin
, V extends TiView> extend
private TiActivityDelegate
mDelegate;
+ private final UiThreadExecutor mUiThreadExecutor = new UiThreadExecutor();
+
/**
* Binds a {@link TiPresenter} returned by the {@link TiPresenterProvider} to the {@link
* Activity} and all future {@link Activity} instances created due to configuration changes.
@@ -118,6 +122,11 @@ public P getRetainedPresenter() {
return null;
}
+ @Override
+ public Executor getUiThreadExecutor() {
+ return mUiThreadExecutor;
+ }
+
/**
* Invalidates the cache of the latest bound view. Forces the next binding of the view to run
* through all the interceptors (again).
@@ -194,11 +203,6 @@ public void onStop() {
mDelegate.onStop_afterSuper();
}
- @Override
- public boolean postToMessageQueue(final Runnable runnable) {
- return getActivity().getWindow().getDecorView().post(runnable);
- }
-
@SuppressWarnings("unchecked")
@NonNull
@Override
diff --git a/plugin/src/main/java/net/grandcentrix/thirtyinch/plugin/TiFragmentPlugin.java b/plugin/src/main/java/net/grandcentrix/thirtyinch/plugin/TiFragmentPlugin.java
index 603e3479..9c074d40 100644
--- a/plugin/src/main/java/net/grandcentrix/thirtyinch/plugin/TiFragmentPlugin.java
+++ b/plugin/src/main/java/net/grandcentrix/thirtyinch/plugin/TiFragmentPlugin.java
@@ -29,6 +29,7 @@
import net.grandcentrix.thirtyinch.internal.TiLoggingTagProvider;
import net.grandcentrix.thirtyinch.internal.TiPresenterProvider;
import net.grandcentrix.thirtyinch.internal.TiViewProvider;
+import net.grandcentrix.thirtyinch.internal.UiThreadExecutor;
import net.grandcentrix.thirtyinch.util.AndroidDeveloperOptions;
import net.grandcentrix.thirtyinch.util.AnnotationUtil;
@@ -41,6 +42,7 @@
import android.view.ViewGroup;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* Adds a {@link TiPresenter} to a Fragment. Can be used for both, {@link Fragment} and
@@ -58,6 +60,8 @@ public class TiFragmentPlugin
, V extends TiView> extend
private TiFragmentDelegate
mDelegate;
+ private final UiThreadExecutor mUiThreadExecutor = new UiThreadExecutor();
+
/**
* Binds a {@link TiPresenter} returned by the {@link TiPresenterProvider} to the {@link
* Fragment} and all future {@link Fragment} instances created due to configuration changes.
@@ -99,7 +103,6 @@ public List getInterceptors(
return mDelegate.getInterceptors(predicate);
}
-
@Override
public String getLoggingTag() {
return TAG;
@@ -109,6 +112,11 @@ public P getPresenter() {
return mDelegate.getPresenter();
}
+ @Override
+ public Executor getUiThreadExecutor() {
+ return mUiThreadExecutor;
+ }
+
/**
* Invalidates the cache of the latest bound view. Forces the next binding of the view to run
* through all the interceptors (again).
@@ -187,11 +195,6 @@ public void onStop() {
super.onStop();
}
- @Override
- public boolean postToMessageQueue(final Runnable runnable) {
- return getFragment().getActivity().getWindow().getDecorView().post(runnable);
- }
-
/**
* the default implementation assumes that the fragment is the view and implements the {@link
* TiView} interface. Override this method for a different behaviour.
diff --git a/rx/src/main/java/net/grandcentrix/thirtyinch/rx/RxTiPresenterUtils.java b/rx/src/main/java/net/grandcentrix/thirtyinch/rx/RxTiPresenterUtils.java
index 889fa050..9d520822 100644
--- a/rx/src/main/java/net/grandcentrix/thirtyinch/rx/RxTiPresenterUtils.java
+++ b/rx/src/main/java/net/grandcentrix/thirtyinch/rx/RxTiPresenterUtils.java
@@ -114,40 +114,37 @@ public Observable call(Observable observable) {
* TiPresenter#attachView(TiView)} and before calling {@link TiPresenter#detachView()}.
*/
public static Observable isViewReady(final TiPresenter presenter) {
- return Observable.create(
- new Observable.OnSubscribe() {
- @Override
- public void call(final Subscriber super Boolean> subscriber) {
- if (!subscriber.isUnsubscribed()) {
- subscriber.onNext(presenter.getState()
- == TiPresenter.State.VIEW_ATTACHED);
- }
-
- final Removable removable = presenter
- .addLifecycleObserver(new TiLifecycleObserver() {
- @Override
- public void onChange(final TiPresenter.State state,
- final boolean hasLifecycleMethodBeenCalled) {
- if (!subscriber.isUnsubscribed()) {
- subscriber.onNext(state
- == TiPresenter.State.VIEW_ATTACHED);
- }
- }
- });
-
- subscriber.add(new Subscription() {
- @Override
- public boolean isUnsubscribed() {
- return removable.isRemoved();
- }
+ return Observable.create(new Observable.OnSubscribe() {
+ @Override
+ public void call(final Subscriber super Boolean> subscriber) {
+ if (!subscriber.isUnsubscribed()) {
+ subscriber.onNext(presenter.getState() == TiPresenter.State.VIEW_ATTACHED);
+ }
+ final Removable removable = presenter
+ .addLifecycleObserver(new TiLifecycleObserver() {
@Override
- public void unsubscribe() {
- removable.remove();
+ public void onChange(final TiPresenter.State state,
+ final boolean hasLifecycleMethodBeenCalled) {
+ if (!subscriber.isUnsubscribed()) {
+ subscriber.onNext(state == TiPresenter.State.VIEW_ATTACHED
+ && hasLifecycleMethodBeenCalled);
+ }
}
});
+
+ subscriber.add(new Subscription() {
+ @Override
+ public boolean isUnsubscribed() {
+ return removable.isRemoved();
+ }
+
+ @Override
+ public void unsubscribe() {
+ removable.remove();
}
- })
- .distinctUntilChanged();
+ });
+ }
+ }).distinctUntilChanged();
}
}
diff --git a/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterUtils.java b/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterUtils.java
index 6de3ad8c..5ae1dfdd 100644
--- a/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterUtils.java
+++ b/rx2/src/main/java/net/grandcentrix/thirtyinch/rx2/RxTiPresenterUtils.java
@@ -32,42 +32,39 @@ public class RxTiPresenterUtils {
* 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 hasLifecycleMethodBeenCalled) {
- if (!emitter.isDisposed()) {
- emitter.onNext(state ==
- TiPresenter.State.VIEW_ATTACHED);
- }
- }
- });
-
- emitter.setDisposable(new Disposable() {
- @Override
- public void dispose() {
- removable.remove();
- }
+ 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 boolean isDisposed() {
- return removable.isRemoved();
+ public void onChange(final TiPresenter.State state,
+ final boolean hasLifecycleMethodBeenCalled) {
+ if (!emitter.isDisposed()) {
+ emitter.onNext(state == TiPresenter.State.VIEW_ATTACHED
+ && hasLifecycleMethodBeenCalled);
+ }
}
});
+
+ emitter.setDisposable(new Disposable() {
+ @Override
+ public void dispose() {
+ removable.remove();
+ }
+
+ @Override
+ public boolean isDisposed() {
+ return removable.isRemoved();
}
- })
- .distinctUntilChanged();
+ });
+ }
+ }).distinctUntilChanged();
}
}
diff --git a/sample/src/main/java/net/grandcentrix/thirtyinch/sample/HelloWorldPresenter.java b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/HelloWorldPresenter.java
index 679dd2d6..f90eed38 100644
--- a/sample/src/main/java/net/grandcentrix/thirtyinch/sample/HelloWorldPresenter.java
+++ b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/HelloWorldPresenter.java
@@ -16,6 +16,7 @@
package net.grandcentrix.thirtyinch.sample;
import net.grandcentrix.thirtyinch.TiPresenter;
+import net.grandcentrix.thirtyinch.ViewAction;
import net.grandcentrix.thirtyinch.rx.RxTiPresenterSubscriptionHandler;
import net.grandcentrix.thirtyinch.rx.RxTiPresenterUtils;
@@ -73,7 +74,12 @@ protected void onCreate() {
.subscribe(new Action1() {
@Override
public void call(final Long uptime) {
- getView().showPresenterUpTime(uptime);
+ sendToView(new ViewAction() {
+ @Override
+ public void call(final HelloWorldView view) {
+ view.showPresenterUpTime(uptime);
+ }
+ });
}
}));
diff --git a/sample/src/main/java/net/grandcentrix/thirtyinch/sample/HelloWorldView.java b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/HelloWorldView.java
index 3d7a3201..674eaf48 100644
--- a/sample/src/main/java/net/grandcentrix/thirtyinch/sample/HelloWorldView.java
+++ b/sample/src/main/java/net/grandcentrix/thirtyinch/sample/HelloWorldView.java
@@ -25,7 +25,6 @@ public interface HelloWorldView extends TiView {
Observable onButtonClicked();
- @CallOnMainThread
void showPresenterUpTime(Long uptime);
@CallOnMainThread
diff --git a/test/src/main/java/net/grandcentrix/thirtyinch/test/TiPresenterInstructor.java b/test/src/main/java/net/grandcentrix/thirtyinch/test/TiPresenterInstructor.java
index 61f7a458..538515e0 100644
--- a/test/src/main/java/net/grandcentrix/thirtyinch/test/TiPresenterInstructor.java
+++ b/test/src/main/java/net/grandcentrix/thirtyinch/test/TiPresenterInstructor.java
@@ -18,6 +18,8 @@
import net.grandcentrix.thirtyinch.TiPresenter;
import net.grandcentrix.thirtyinch.TiView;
+import java.util.concurrent.Executor;
+
public class TiPresenterInstructor {
private TiPresenter mPresenter;
@@ -32,6 +34,12 @@ public TiPresenterInstructor(final TiPresenter presenter) {
public void attachView(final V view) {
detachView();
+ mPresenter.setUiThreadExecutor(new Executor() {
+ @Override
+ public void execute(final Runnable action) {
+ action.run();
+ }
+ });
mPresenter.attachView(view);
}
@@ -59,6 +67,7 @@ public void detachView() {
break;
case VIEW_ATTACHED:
mPresenter.detachView();
+ mPresenter.setUiThreadExecutor(null);
break;
case DESTROYED:
throw new IllegalStateException(
diff --git a/thirtyinch/src/androidTest/java/net/grandcentrix/thirtyinch/internal/TiActivityDelegateTest.java b/thirtyinch/src/androidTest/java/net/grandcentrix/thirtyinch/internal/TiActivityDelegateTest.java
index 1fa5eff1..134a7a32 100644
--- a/thirtyinch/src/androidTest/java/net/grandcentrix/thirtyinch/internal/TiActivityDelegateTest.java
+++ b/thirtyinch/src/androidTest/java/net/grandcentrix/thirtyinch/internal/TiActivityDelegateTest.java
@@ -29,6 +29,8 @@
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import java.util.concurrent.Executor;
+
import static junit.framework.Assert.assertEquals;
@RunWith(AndroidJUnit4.class)
@@ -239,9 +241,13 @@ public boolean isDontKeepActivitiesEnabled() {
}
@Override
- public boolean postToMessageQueue(final Runnable action) {
- action.run();
- return true;
+ public Executor getUiThreadExecutor() {
+ return new Executor() {
+ @Override
+ public void execute(@NonNull final Runnable action) {
+ action.run();
+ }
+ };
}
},
new TiViewProvider() {
diff --git a/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/TiActivity.java b/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/TiActivity.java
index c8f37f01..700f4606 100644
--- a/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/TiActivity.java
+++ b/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/TiActivity.java
@@ -22,6 +22,7 @@
import net.grandcentrix.thirtyinch.internal.TiLoggingTagProvider;
import net.grandcentrix.thirtyinch.internal.TiPresenterProvider;
import net.grandcentrix.thirtyinch.internal.TiViewProvider;
+import net.grandcentrix.thirtyinch.internal.UiThreadExecutor;
import net.grandcentrix.thirtyinch.util.AndroidDeveloperOptions;
import net.grandcentrix.thirtyinch.util.AnnotationUtil;
@@ -32,6 +33,7 @@
import android.support.v7.app.AppCompatActivity;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* Created by pascalwelsch on 9/8/15.
@@ -48,6 +50,8 @@ public abstract class TiActivity
, V extends TiView>
private final TiActivityDelegate
mDelegate
= new TiActivityDelegate<>(this, this, this, this);
+ private final UiThreadExecutor mUiThreadExecutor = new UiThreadExecutor();
+
@NonNull
@Override
public Removable addBindViewInterceptor(@NonNull final BindViewInterceptor interceptor) {
@@ -90,6 +94,11 @@ public P getRetainedPresenter() {
return null;
}
+ @Override
+ public Executor getUiThreadExecutor() {
+ return mUiThreadExecutor;
+ }
+
/**
* Invalidates the cache of the latest bound view. Forces the next binding of the view to run
* through all the interceptors (again).
@@ -136,11 +145,6 @@ public Object onRetainCustomNonConfigurationInstance() {
return null;
}
- @Override
- public boolean postToMessageQueue(final Runnable runnable) {
- return getWindow().getDecorView().post(runnable);
- }
-
@SuppressWarnings("unchecked")
@NonNull
@Override
diff --git a/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/TiDialogFragment.java b/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/TiDialogFragment.java
index 7d4d7338..ed9bf3fc 100644
--- a/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/TiDialogFragment.java
+++ b/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/TiDialogFragment.java
@@ -21,6 +21,7 @@
import net.grandcentrix.thirtyinch.internal.TiLoggingTagProvider;
import net.grandcentrix.thirtyinch.internal.TiPresenterProvider;
import net.grandcentrix.thirtyinch.internal.TiViewProvider;
+import net.grandcentrix.thirtyinch.internal.UiThreadExecutor;
import net.grandcentrix.thirtyinch.util.AndroidDeveloperOptions;
import net.grandcentrix.thirtyinch.util.AnnotationUtil;
@@ -33,6 +34,7 @@
import android.view.ViewGroup;
import java.util.List;
+import java.util.concurrent.Executor;
public abstract class TiDialogFragment
, V extends TiView>
extends AppCompatDialogFragment
@@ -74,6 +76,11 @@ public P getPresenter() {
return mDelegate.getPresenter();
}
+ @Override
+ public Executor getUiThreadExecutor() {
+ return new UiThreadExecutor();
+ }
+
/**
* Invalidates the cache of the latest bound view. Forces the next binding of the view to run
* through all the interceptors (again).
@@ -152,11 +159,6 @@ public void onStop() {
super.onStop();
}
- @Override
- public boolean postToMessageQueue(final Runnable runnable) {
- return getActivity().getWindow().getDecorView().post(runnable);
- }
-
/**
* the default implementation assumes that the fragment is the view and implements the {@link
* TiView} interface. Override this method for a different behaviour.
diff --git a/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/TiFragment.java b/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/TiFragment.java
index 9a0567bc..51422478 100644
--- a/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/TiFragment.java
+++ b/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/TiFragment.java
@@ -21,6 +21,7 @@
import net.grandcentrix.thirtyinch.internal.TiLoggingTagProvider;
import net.grandcentrix.thirtyinch.internal.TiPresenterProvider;
import net.grandcentrix.thirtyinch.internal.TiViewProvider;
+import net.grandcentrix.thirtyinch.internal.UiThreadExecutor;
import net.grandcentrix.thirtyinch.util.AndroidDeveloperOptions;
import net.grandcentrix.thirtyinch.util.AnnotationUtil;
@@ -33,6 +34,7 @@
import android.view.ViewGroup;
import java.util.List;
+import java.util.concurrent.Executor;
public abstract class TiFragment
, V extends TiView> extends Fragment
implements DelegatedTiFragment, TiPresenterProvider
, TiLoggingTagProvider,
@@ -45,6 +47,8 @@ public abstract class TiFragment
, V extends TiView> ext
private final TiFragmentDelegate
mDelegate =
new TiFragmentDelegate<>(this, this, this, this);
+ private final UiThreadExecutor mUiThreadExecutor = new UiThreadExecutor();
+
@NonNull
@Override
public Removable addBindViewInterceptor(@NonNull final BindViewInterceptor interceptor) {
@@ -73,6 +77,11 @@ public P getPresenter() {
return mDelegate.getPresenter();
}
+ @Override
+ public Executor getUiThreadExecutor() {
+ return mUiThreadExecutor;
+ }
+
/**
* Invalidates the cache of the latest bound view. Forces the next binding of the view to run
* through all the interceptors (again).
@@ -151,11 +160,6 @@ public void onStop() {
super.onStop();
}
- @Override
- public boolean postToMessageQueue(final Runnable runnable) {
- return getActivity().getWindow().getDecorView().post(runnable);
- }
-
/**
* the default implementation assumes that the fragment is the view and implements the {@link
* TiView} interface. Override this method for a different behaviour.
diff --git a/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/TiPresenter.java b/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/TiPresenter.java
index 276ed6ba..4ff8ca00 100644
--- a/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/TiPresenter.java
+++ b/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/TiPresenter.java
@@ -28,6 +28,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
+import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
/**
@@ -89,6 +90,12 @@ public enum State {
private State mState = State.INITIALIZED;
+ /**
+ * Executor for UI operations, must be set by the view implementation
+ */
+ @Nullable
+ private Executor mUiThreadExecutor;
+
private V mView;
public static void setDefaultConfig(final TiConfiguration config) {
@@ -109,7 +116,9 @@ public TiPresenter(final TiConfiguration config) {
}
/**
- * Observes the lifecycle state of this presenter.
+ * Observes the lifecycle state of this presenter. Observers get called in order they are
+ * added for constructive events and in reversed order for destructive events. First in, last
+ * out.
*
* @param observer called when lifecycle state changes after the lifecycle method such as
* {@link
@@ -187,6 +196,8 @@ public void attachView(@NonNull final V view) {
+ " did not call through to super.onWakeUp()");
}
moveToState(State.VIEW_ATTACHED, true);
+
+ sendPostponedActionsToView(view);
}
/**
@@ -315,6 +326,43 @@ public boolean isViewAttached() {
return mState == State.VIEW_ATTACHED;
}
+ /**
+ * Runs the specified action on the UI thread. It only works when a view is attached
+ *
+ * When you are looking for a way to execute code when the view got available in the future
+ * have a look at {@link #sendToView(ViewAction)}
+ *
+ * @param action the action to run on the UI thread
+ * @throws IllegalStateException when the executor is not available (most likely because the
+ * view is not attached)
+ */
+ public void runOnUiThread(@NonNull final Runnable action) {
+ if (mUiThreadExecutor != null) {
+ mUiThreadExecutor.execute(action);
+ } else {
+ if (getView() == null) {
+ throw new IllegalStateException("view is not attached, "
+ + "no executor available to run ui interactions on");
+ } else {
+ throw new IllegalStateException("no ui thread executor available");
+ }
+ }
+ }
+
+ /**
+ * sets the Executor used for the {@link #runOnUiThread(Runnable)} method.
+ *
+ * This Executor is most likely the {@link net.grandcentrix.thirtyinch.internal.UiThreadExecutor}
+ * posting the work on the Android Main Thread.
+ * When using the {@code TiPresenterInstructor} in your tests an {@link Executor} for the
+ * current {@link Thread} is used, therefore all executed actions run synchronous.
+ *
+ * @param uiThreadExecutor executor for view interactions
+ */
+ public void setUiThreadExecutor(@Nullable final Executor uiThreadExecutor) {
+ mUiThreadExecutor = uiThreadExecutor;
+ }
+
@Override
public String toString() {
final String viewName;
@@ -350,11 +398,6 @@ protected void onAttachView(@NonNull V view) {
"don't call #onAttachView(TiView) directly, call #attachView(TiView)");
}
mCalled = true;
-
- // send all queued actions since the view was detached to the new view.
- // It's part of the super call because there might be usecases where the implementer
- // wants to execute actions on the view before executing the queued ones.
- sendPostponedActionsToView(view);
}
/**
@@ -424,7 +467,7 @@ protected void onWakeUp() {
}
/**
- * Executes the {@link ViewAction} when the view is available.
+ * Executes the {@link ViewAction} when the view is available on the UI thread.
* Once a view is attached the actions get called in the same order they have been added.
* When the view is already attached the action will be executed immediately.
*
@@ -445,10 +488,15 @@ protected void onWakeUp() {
* @see #sendPostponedActionsToView
* @see #onAttachView(TiView)
*/
- protected void sendToView(ViewAction action) {
+ protected void sendToView(final ViewAction action) {
final V view = getView();
if (view != null) {
- action.call(view);
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ action.call(view);
+ }
+ });
} else {
mPostponedViewActions.add(action);
}
@@ -506,8 +554,20 @@ private void moveToState(final State newState, final boolean hasLifecycleMethodB
mState = newState;
}
- for (int i = 0; i < mLifecycleObservers.size(); i++) {
- mLifecycleObservers.get(i).onChange(newState, hasLifecycleMethodBeenCalled);
+ switch (newState) {
+ case INITIALIZED:
+ case VIEW_ATTACHED:
+ for (int i = 0; i < mLifecycleObservers.size(); i++) {
+ mLifecycleObservers.get(i).onChange(newState, hasLifecycleMethodBeenCalled);
+ }
+ break;
+
+ case VIEW_DETACHED:
+ case DESTROYED:
+ // reverse observer order for teardown events; first in, last out
+ for (int i = mLifecycleObservers.size() - 1; i >= 0; i--) {
+ mLifecycleObservers.get(i).onChange(newState, hasLifecycleMethodBeenCalled);
+ }
}
}
@@ -516,7 +576,7 @@ private void moveToState(final State newState, final boolean hasLifecycleMethodB
*
* @param view where the actions will be sent to
*/
- private void sendPostponedActionsToView(V view) {
+ private void sendPostponedActionsToView(@NonNull final V view) {
while (!mPostponedViewActions.isEmpty()) {
mPostponedViewActions.poll().call(view);
}
diff --git a/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/internal/DelegatedTiActivity.java b/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/internal/DelegatedTiActivity.java
index 8acbf657..00f76680 100644
--- a/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/internal/DelegatedTiActivity.java
+++ b/thirtyinch/src/main/java/net/grandcentrix/thirtyinch/internal/DelegatedTiActivity.java
@@ -19,6 +19,8 @@
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
+import java.util.concurrent.Executor;
+
/**
* This interface, implemented by Activities allows easy testing of the {@link TiActivityDelegate}
* without mocking Android classes such as {@link Activity}
@@ -32,6 +34,11 @@ public interface DelegatedTiActivity