Don't defer dispatching of events while paused

Reviewed By: astreet

Differential Revision: D3186718

fb-gh-sync-id: 888c6e0cc0b52edbbc6b9e0cb285ce1a2d1bf987
fbshipit-source-id: 888c6e0cc0b52edbbc6b9e0cb285ce1a2d1bf987
This commit is contained in:
Chris Hopman 2016-04-25 12:45:37 -07:00 committed by Facebook Github Bot 8
parent 8e7ea1179a
commit 860b7ddc35
1 changed files with 46 additions and 21 deletions

View File

@ -96,7 +96,7 @@ public class EventDispatcher implements LifecycleEventListener {
private Event[] mEventsToDispatch = new Event[16]; private Event[] mEventsToDispatch = new Event[16];
private int mEventsToDispatchSize = 0; private int mEventsToDispatchSize = 0;
private @Nullable RCTEventEmitter mRCTEventEmitter; private @Nullable RCTEventEmitter mRCTEventEmitter;
private volatile @Nullable ScheduleDispatchFrameCallback mCurrentFrameCallback; private final ScheduleDispatchFrameCallback mCurrentFrameCallback;
private short mNextEventTypeId = 0; private short mNextEventTypeId = 0;
private volatile boolean mHasDispatchScheduled = false; private volatile boolean mHasDispatchScheduled = false;
private volatile int mHasDispatchScheduledCount = 0; private volatile int mHasDispatchScheduledCount = 0;
@ -104,6 +104,7 @@ public class EventDispatcher implements LifecycleEventListener {
public EventDispatcher(ReactApplicationContext reactContext) { public EventDispatcher(ReactApplicationContext reactContext) {
mReactContext = reactContext; mReactContext = reactContext;
mReactContext.addLifecycleEventListener(this); mReactContext.addLifecycleEventListener(this);
mCurrentFrameCallback = new ScheduleDispatchFrameCallback();
} }
/** /**
@ -118,42 +119,37 @@ public class EventDispatcher implements LifecycleEventListener {
event.getEventName(), event.getEventName(),
event.getUniqueID()); event.getUniqueID());
} }
// If the host activity is paused, the frame callback may not be currently
// posted. Ensure that it is so that this event gets delivered promptly.
mCurrentFrameCallback.maybePostFromNonUI();
} }
@Override @Override
public void onHostResume() { public void onHostResume() {
UiThreadUtil.assertOnUiThread(); UiThreadUtil.assertOnUiThread();
Assertions.assumeCondition(mCurrentFrameCallback == null);
if (mRCTEventEmitter == null) { if (mRCTEventEmitter == null) {
mRCTEventEmitter = mReactContext.getJSModule(RCTEventEmitter.class); mRCTEventEmitter = mReactContext.getJSModule(RCTEventEmitter.class);
} }
mCurrentFrameCallback.maybePost();
mCurrentFrameCallback = new ScheduleDispatchFrameCallback();
ReactChoreographer.getInstance()
.postFrameCallback(ReactChoreographer.CallbackType.TIMERS_EVENTS, mCurrentFrameCallback);
} }
@Override @Override
public void onHostPause() { public void onHostPause() {
clearFrameCallback(); stopFrameCallback();
} }
@Override @Override
public void onHostDestroy() { public void onHostDestroy() {
clearFrameCallback(); stopFrameCallback();
} }
public void onCatalystInstanceDestroyed() { public void onCatalystInstanceDestroyed() {
clearFrameCallback(); stopFrameCallback();
} }
private void clearFrameCallback() { private void stopFrameCallback() {
UiThreadUtil.assertOnUiThread(); UiThreadUtil.assertOnUiThread();
if (mCurrentFrameCallback != null) { mCurrentFrameCallback.stop();
mCurrentFrameCallback.stop();
mCurrentFrameCallback = null;
}
} }
/** /**
@ -229,7 +225,7 @@ public class EventDispatcher implements LifecycleEventListener {
} }
private class ScheduleDispatchFrameCallback implements Choreographer.FrameCallback { private class ScheduleDispatchFrameCallback implements Choreographer.FrameCallback {
private volatile boolean mIsPosted = false;
private boolean mShouldStop = false; private boolean mShouldStop = false;
@Override @Override
@ -237,14 +233,16 @@ public class EventDispatcher implements LifecycleEventListener {
UiThreadUtil.assertOnUiThread(); UiThreadUtil.assertOnUiThread();
if (mShouldStop) { if (mShouldStop) {
return; mIsPosted = false;
} else {
post();
} }
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ScheduleDispatchFrameCallback"); Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ScheduleDispatchFrameCallback");
try { try {
moveStagedEventsToDispatchQueue(); moveStagedEventsToDispatchQueue();
if (!mHasDispatchScheduled) { if (mEventsToDispatchSize > 0 && !mHasDispatchScheduled) {
mHasDispatchScheduled = true; mHasDispatchScheduled = true;
Systrace.startAsyncFlow( Systrace.startAsyncFlow(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
@ -252,9 +250,6 @@ public class EventDispatcher implements LifecycleEventListener {
mHasDispatchScheduledCount); mHasDispatchScheduledCount);
mReactContext.runOnJSQueueThread(mDispatchEventsRunnable); mReactContext.runOnJSQueueThread(mDispatchEventsRunnable);
} }
ReactChoreographer.getInstance()
.postFrameCallback(ReactChoreographer.CallbackType.TIMERS_EVENTS, this);
} finally { } finally {
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
} }
@ -263,6 +258,36 @@ public class EventDispatcher implements LifecycleEventListener {
public void stop() { public void stop() {
mShouldStop = true; mShouldStop = true;
} }
public void maybePost() {
if (!mIsPosted) {
mIsPosted = true;
post();
}
}
private void post() {
ReactChoreographer.getInstance()
.postFrameCallback(ReactChoreographer.CallbackType.TIMERS_EVENTS, mCurrentFrameCallback);
}
public void maybePostFromNonUI() {
if (mIsPosted) {
return;
}
// We should only hit this slow path when we receive events while the host activity is paused.
if (mReactContext.isOnUiQueueThread()) {
maybePost();
} else {
mReactContext.runOnUiQueueThread(new Runnable() {
@Override
public void run() {
maybePost();
}
});
}
}
} }
private class DispatchEventsRunnable implements Runnable { private class DispatchEventsRunnable implements Runnable {