diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java index 537f1bfb4..ced642e4e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java @@ -96,7 +96,7 @@ public class EventDispatcher implements LifecycleEventListener { private Event[] mEventsToDispatch = new Event[16]; private int mEventsToDispatchSize = 0; private @Nullable RCTEventEmitter mRCTEventEmitter; - private volatile @Nullable ScheduleDispatchFrameCallback mCurrentFrameCallback; + private final ScheduleDispatchFrameCallback mCurrentFrameCallback; private short mNextEventTypeId = 0; private volatile boolean mHasDispatchScheduled = false; private volatile int mHasDispatchScheduledCount = 0; @@ -104,6 +104,7 @@ public class EventDispatcher implements LifecycleEventListener { public EventDispatcher(ReactApplicationContext reactContext) { mReactContext = reactContext; mReactContext.addLifecycleEventListener(this); + mCurrentFrameCallback = new ScheduleDispatchFrameCallback(); } /** @@ -118,42 +119,37 @@ public class EventDispatcher implements LifecycleEventListener { event.getEventName(), 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 public void onHostResume() { UiThreadUtil.assertOnUiThread(); - Assertions.assumeCondition(mCurrentFrameCallback == null); - if (mRCTEventEmitter == null) { mRCTEventEmitter = mReactContext.getJSModule(RCTEventEmitter.class); } - - mCurrentFrameCallback = new ScheduleDispatchFrameCallback(); - ReactChoreographer.getInstance() - .postFrameCallback(ReactChoreographer.CallbackType.TIMERS_EVENTS, mCurrentFrameCallback); + mCurrentFrameCallback.maybePost(); } @Override public void onHostPause() { - clearFrameCallback(); + stopFrameCallback(); } @Override public void onHostDestroy() { - clearFrameCallback(); + stopFrameCallback(); } public void onCatalystInstanceDestroyed() { - clearFrameCallback(); + stopFrameCallback(); } - private void clearFrameCallback() { + private void stopFrameCallback() { UiThreadUtil.assertOnUiThread(); - if (mCurrentFrameCallback != null) { - mCurrentFrameCallback.stop(); - mCurrentFrameCallback = null; - } + mCurrentFrameCallback.stop(); } /** @@ -229,7 +225,7 @@ public class EventDispatcher implements LifecycleEventListener { } private class ScheduleDispatchFrameCallback implements Choreographer.FrameCallback { - + private volatile boolean mIsPosted = false; private boolean mShouldStop = false; @Override @@ -237,14 +233,16 @@ public class EventDispatcher implements LifecycleEventListener { UiThreadUtil.assertOnUiThread(); if (mShouldStop) { - return; + mIsPosted = false; + } else { + post(); } Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ScheduleDispatchFrameCallback"); try { moveStagedEventsToDispatchQueue(); - if (!mHasDispatchScheduled) { + if (mEventsToDispatchSize > 0 && !mHasDispatchScheduled) { mHasDispatchScheduled = true; Systrace.startAsyncFlow( Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, @@ -252,9 +250,6 @@ public class EventDispatcher implements LifecycleEventListener { mHasDispatchScheduledCount); mReactContext.runOnJSQueueThread(mDispatchEventsRunnable); } - - ReactChoreographer.getInstance() - .postFrameCallback(ReactChoreographer.CallbackType.TIMERS_EVENTS, this); } finally { Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); } @@ -263,6 +258,36 @@ public class EventDispatcher implements LifecycleEventListener { public void stop() { 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 {