NativeAnimatedModule: animations should still run if there isn't a Fabric commit for multiple frames

Summary:
See videos. In some cases when an `Animated.timing` animation was triggered, there are not necessarily any corresponding Fabric commits. This causes the animations to be queued up but never execute... until there's some Fabric commit at a distant point in the future.

We can't immediately flush all animation operations (see inline comments) but we also shouldn't wait forever. Thus, we wait 2 frames and then flush.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D22490650

fbshipit-source-id: 1669bfed00f2a92b50f9558fc7ccaf71dc636980
This commit is contained in:
Joshua Gross
2020-07-10 23:32:37 -07:00
committed by Facebook GitHub Bot
parent 7bf56e1902
commit 46d6e7f575
@@ -103,6 +103,7 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
private @Nullable NativeAnimatedNodesManager mNodesManager;
private volatile boolean mFabricBatchCompleted = false;
private int mFabricFramesSkipped = 0;
private boolean mInitializedForFabric = false;
private boolean mInitializedForNonFabric = false;
private @UIManagerType int mUIManagerType = UIManagerType.DEFAULT;
@@ -174,17 +175,29 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
return;
}
if (mFabricBatchCompleted) {
// This will execute all operations and preOperations queued
// since the last time this was run, and will race with anything
// being queued from the JS thread. That is, if the JS thread
// is still queuing operations, we might execute some of them
// at the very end until we exhaust the queue faster than the
// JS thread can queue up new items.
executeAllOperations(mPreOperations);
executeAllOperations(mOperations);
mFabricBatchCompleted = false;
// The problem we're trying to solve here: we could be in the middle of queueing
// a batch of related animation operations when Fabric flushes a batch of MountItems.
// It's visually bad if we execute half of the animation ops and then wait another frame
// (or more) to execute the rest.
// Therefore, we wait until either `didScheduleMountItems` has been called, or a certain
// number of frames have been skipped.
// We wait a max of 2 frames or about 32ms before flushing.
// The reason to execute in some cases without a Fabric commit is that there might be
// animations that are triggered without any Fabric commits.
if (!mFabricBatchCompleted && mFabricFramesSkipped < 3) {
mFabricFramesSkipped++;
}
// This will execute all operations and preOperations queued
// since the last time this was run, and will race with anything
// being queued from the JS thread. That is, if the JS thread
// is still queuing operations, we might execute some of them
// at the very end until we exhaust the queue faster than the
// JS thread can queue up new items.
executeAllOperations(mPreOperations);
executeAllOperations(mOperations);
mFabricBatchCompleted = false;
mFabricFramesSkipped = 0;
}
private void executeAllOperations(Queue<UIThreadOperation> operationQueue) {