Skip to content
This repository was archived by the owner on Mar 16, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ public enum State {

private LinkedBlockingQueue<ViewAction<V>> mPostponedViewActions = new LinkedBlockingQueue<>();

/**
* view is attached and all {@link #mLifecycleObservers} have been notified about the attache
* event. The view is now in a "running" state
*
* This is a temporary field without public getter until the presenter state and notifications
* get completely refactored
*/
private volatile boolean mRunning = false;

private State mState = State.INITIALIZED;

/**
Expand Down Expand Up @@ -198,6 +207,10 @@ public void attachView(@NonNull final V view) {
}
moveToState(State.VIEW_ATTACHED, true);

// TODO refactor events and add a new state HERE when the view is attached and prepared by all observers.
// Calling this a "running" state for now, prevents executing postponed actions before this point
mRunning = true;

sendPostponedActionsToView(view);
}

Expand Down Expand Up @@ -269,6 +282,7 @@ public final void detachView() {
TiLog.v(TAG, "not calling onDetachView(), not woken up");
return;
}
mRunning = false;
moveToState(State.VIEW_DETACHED, false);
mCalled = false;
TiLog.v(TAG, "deprecated onSleep()");
Expand Down Expand Up @@ -515,7 +529,7 @@ protected void onWakeUp() {
*/
protected void sendToView(final ViewAction<V> action) {
final V view = getView();
if (view != null) {
if (mRunning) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@
import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertTrue;
import static org.assertj.core.api.Java6Assertions.assertThat;
import static org.assertj.core.api.Java6Assertions.failBecauseExceptionWasNotThrown;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
Expand Down Expand Up @@ -97,6 +99,68 @@ public void call(final TestView view) {
inOrder.verify(view).doSomething2();
}

@Test
public void sendToView_fires_after_view_and_executor_are_ready() throws Exception {

// Given a presenter without attached view
final TestPresenter presenter = new TestPresenter();
presenter.create();
final TestView view = mock(TestView.class);

// When calling sendToView
presenter.sendToView(new ViewAction<TestView>() {
@Override
public void call(final TestView testView) {
testView.doSomething1();
}
});
// Then the action will be postponed and not executed
verify(view, never()).doSomething1();

// When setting an executor
presenter.setUiThreadExecutor(new Executor() {
@Override
public void execute(@NonNull final Runnable command) {
command.run();
}
});
// The postponed actions will not be executed immediately, no view is attached
verify(view, never()).doSomething1();

// When view and executor are both attached
presenter.attachView(view);
// The postponed actions will be executed
verify(view).doSomething1();
}

@Test
public void sendToView_withRunningView_crashes_without_uiThreadExecutor() throws Exception {

// Given a presenter with a attached view (running state)
// No uiThreadExecutor is attached
final TestPresenter presenter = new TestPresenter();
presenter.create();
final TestView view = mock(TestView.class);
presenter.attachView(view);

// When calling sendToView without attaching a uiThreadExecutor
try {
presenter.sendToView(new ViewAction<TestView>() {
@Override
public void call(final TestView testView) {
testView.doSomething1();
}
});
failBecauseExceptionWasNotThrown(IllegalStateException.class);
} catch (IllegalStateException e) {
// Then an Exception is thrown
// Whoever creates and manages the TiPresenter has to provide an executor
assertThat(e).hasMessageContaining("no ui thread executor");
}

verify(view, never()).doSomething1();
}

@Test
public void testSendToViewRunsOnTheMainThread() throws Exception {

Expand Down