mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Android Animated timing: interface-only
Summary: This is (part of) a rewrite of D15390384. This implements the lifecycle interface only for Fabric to signal to NativeAnimatedModule when preOperations are about to run / operations are about to be dispatched. We will likely want to remove this mechanism entirely and rewrite NativeAnimatedModule in C++ for Fabric/Venice, but for now, I'm not sure of a better solution to unblock. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D21698193 fbshipit-source-id: a13d445073911fd63d896202a7a1bfbe1167038a
This commit is contained in:
committed by
Facebook GitHub Bot
parent
8d6cc50d77
commit
0b00d92514
@@ -8,6 +8,7 @@
|
||||
package com.facebook.react.animated;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.fbreact.specs.NativeAnimatedModuleSpec;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
@@ -16,6 +17,8 @@ import com.facebook.react.bridge.Callback;
|
||||
import com.facebook.react.bridge.LifecycleEventListener;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.UIManager;
|
||||
import com.facebook.react.bridge.UIManagerListener;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.common.annotations.VisibleForTesting;
|
||||
@@ -26,7 +29,6 @@ import com.facebook.react.uimanager.GuardedFrameCallback;
|
||||
import com.facebook.react.uimanager.NativeViewHierarchyManager;
|
||||
import com.facebook.react.uimanager.UIBlock;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.UIManagerModuleListener;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
@@ -75,7 +77,7 @@ import java.util.ArrayList;
|
||||
*/
|
||||
@ReactModule(name = NativeAnimatedModule.NAME)
|
||||
public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
||||
implements LifecycleEventListener, UIManagerModuleListener {
|
||||
implements LifecycleEventListener, UIManagerListener {
|
||||
|
||||
public static final String NAME = "NativeAnimatedModule";
|
||||
|
||||
@@ -132,7 +134,7 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
||||
reactApplicationContext.addLifecycleEventListener(this);
|
||||
UIManagerModule uiManager =
|
||||
Assertions.assertNotNull(reactApplicationContext.getNativeModule(UIManagerModule.class));
|
||||
uiManager.addUIManagerListener(this);
|
||||
uiManager.addUIManagerEventListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,8 +143,19 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
||||
enqueueFrameCallback();
|
||||
}
|
||||
|
||||
// For FabricUIManager
|
||||
@Override
|
||||
public void willDispatchViewUpdates(final UIManagerModule uiManager) {
|
||||
public void willDispatchPreMountItems() {}
|
||||
|
||||
// For FabricUIManager
|
||||
@Override
|
||||
@UiThread
|
||||
public void willDispatchMountItems() {}
|
||||
|
||||
// For non-FabricUIManager
|
||||
@Override
|
||||
@UiThread
|
||||
public void willDispatchViewUpdates(final UIManager uiManager) {
|
||||
if (mOperations.isEmpty() && mPreOperations.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -150,7 +163,15 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
||||
final ArrayList<UIThreadOperation> operations = mOperations;
|
||||
mPreOperations = new ArrayList<>();
|
||||
mOperations = new ArrayList<>();
|
||||
uiManager.prependUIBlock(
|
||||
|
||||
// This is kind of a hack. Basically UIManagerListener cannot import UIManagerModule
|
||||
// (that would cause an import cycle) and they're not in the same package. But,
|
||||
// UIManagerModule is the only thing that calls `willDispatchViewUpdates` so we
|
||||
// know this is safe.
|
||||
// This goes away entirely in Fabric/Venice.
|
||||
UIManagerModule uiManagerModule = (UIManagerModule) uiManager;
|
||||
|
||||
uiManagerModule.prependUIBlock(
|
||||
new UIBlock() {
|
||||
@Override
|
||||
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
|
||||
@@ -160,7 +181,7 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
||||
}
|
||||
}
|
||||
});
|
||||
uiManager.addUIBlock(
|
||||
uiManagerModule.addUIBlock(
|
||||
new UIBlock() {
|
||||
@Override
|
||||
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
|
||||
|
||||
@@ -91,4 +91,19 @@ public interface UIManager extends JSIModule, PerformanceCounter {
|
||||
* @param eventType
|
||||
*/
|
||||
void sendAccessibilityEvent(int reactTag, int eventType);
|
||||
|
||||
/**
|
||||
* Register a {@link UIManagerListener} with this UIManager to receive lifecycle callbacks.
|
||||
*
|
||||
* @param listener
|
||||
*/
|
||||
void addUIManagerEventListener(UIManagerListener listener);
|
||||
|
||||
/**
|
||||
* Unregister a {@link UIManagerListener} from this UIManager to stop receiving lifecycle
|
||||
* callbacks.
|
||||
*
|
||||
* @param listener
|
||||
*/
|
||||
void removeUIManagerEventListener(UIManagerListener listener);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
/** Listener used to hook into the UIManager update process. */
|
||||
public interface UIManagerListener {
|
||||
/**
|
||||
* Called right before view updates are dispatched at the end of a batch. This is useful if a
|
||||
* module needs to add UIBlocks to the queue before it is flushed.
|
||||
*/
|
||||
void willDispatchViewUpdates(UIManager uiManager);
|
||||
/** Called on the UI thread right before normal mount items are executed. */
|
||||
void willDispatchMountItems();
|
||||
/** Called on the UI thread right before premount items are executed. */
|
||||
void willDispatchPreMountItems();
|
||||
}
|
||||
@@ -42,6 +42,7 @@ import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.RetryableMountingLayerException;
|
||||
import com.facebook.react.bridge.UIManager;
|
||||
import com.facebook.react.bridge.UIManagerListener;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.config.ReactFeatureFlags;
|
||||
@@ -82,6 +83,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
@SuppressLint("MissingNativeLoadLibrary")
|
||||
public class FabricUIManager implements UIManager, LifecycleEventListener {
|
||||
@@ -123,6 +125,9 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
|
||||
@NonNull
|
||||
private List<DispatchCommandMountItem> mViewCommandMountItems = new ArrayList<>();
|
||||
|
||||
@NonNull
|
||||
private final CopyOnWriteArrayList<UIManagerListener> mListeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
@GuardedBy("mMountItemsLock")
|
||||
@NonNull
|
||||
private List<MountItem> mMountItems = new ArrayList<>();
|
||||
@@ -500,6 +505,14 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
|
||||
}
|
||||
}
|
||||
|
||||
public void addUIManagerEventListener(UIManagerListener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeUIManagerEventListener(UIManagerListener listener) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method enqueues UI operations directly to the UI thread. This might change in the future
|
||||
* to enforce execution order using {@link ReactChoreographer#CallbackType}.
|
||||
@@ -581,6 +594,10 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
|
||||
return;
|
||||
}
|
||||
|
||||
for (UIManagerListener listener : mListeners) {
|
||||
listener.willDispatchMountItems();
|
||||
}
|
||||
|
||||
final boolean didDispatchItems;
|
||||
try {
|
||||
didDispatchItems = dispatchMountItems();
|
||||
@@ -794,6 +811,10 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
|
||||
// reentering during dispatchPreMountItems
|
||||
mInDispatch = true;
|
||||
|
||||
for (UIManagerListener listener : mListeners) {
|
||||
listener.willDispatchPreMountItems();
|
||||
}
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
long timeLeftInFrame = FRAME_TIME_MS - ((System.nanoTime() - frameTimeNanos) / 1000000);
|
||||
|
||||
@@ -34,6 +34,7 @@ import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.ReadableType;
|
||||
import com.facebook.react.bridge.UIManager;
|
||||
import com.facebook.react.bridge.UIManagerListener;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
@@ -117,6 +118,7 @@ public class UIManagerModule extends ReactContextBaseJavaModule
|
||||
private final UIImplementation mUIImplementation;
|
||||
private final MemoryTrimCallback mMemoryTrimCallback = new MemoryTrimCallback();
|
||||
private final List<UIManagerModuleListener> mListeners = new ArrayList<>();
|
||||
private final List<UIManagerListener> mUIManagerListeners = new ArrayList<>();
|
||||
private @Nullable Map<String, WritableMap> mViewManagerConstantsCache;
|
||||
private volatile int mViewManagerConstantsCacheSize;
|
||||
|
||||
@@ -793,6 +795,9 @@ public class UIManagerModule extends ReactContextBaseJavaModule
|
||||
for (UIManagerModuleListener listener : mListeners) {
|
||||
listener.willDispatchViewUpdates(this);
|
||||
}
|
||||
for (UIManagerListener listener : mUIManagerListeners) {
|
||||
listener.willDispatchViewUpdates(this);
|
||||
}
|
||||
try {
|
||||
mUIImplementation.dispatchViewUpdates(batchId);
|
||||
} finally {
|
||||
@@ -850,14 +855,24 @@ public class UIManagerModule extends ReactContextBaseJavaModule
|
||||
mUIImplementation.prependUIBlock(block);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void addUIManagerListener(UIManagerModuleListener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void removeUIManagerListener(UIManagerModuleListener listener) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void addUIManagerEventListener(UIManagerListener listener) {
|
||||
mUIManagerListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeUIManagerEventListener(UIManagerListener listener) {
|
||||
mUIManagerListeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a reactTag from a component, find its root node tag, if possible. Otherwise, this will
|
||||
* return 0. If the reactTag belongs to a root node, this will return the same reactTag.
|
||||
|
||||
+5
-1
@@ -7,7 +7,11 @@
|
||||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
/** Listener used to hook into the UIManager update process. */
|
||||
/**
|
||||
* Listener used to hook into the UIManager update process. Deprecated: use UIManagerListener
|
||||
* instead. This will be deleted in some future release.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface UIManagerModuleListener {
|
||||
/**
|
||||
* Called right before view updates are dispatched at the end of a batch. This is useful if a
|
||||
|
||||
Reference in New Issue
Block a user