Skip to content

Commit 1e6f79d

Browse files
rubennortefacebook-github-bot
authored andcommitted
Implement mount hooks in UIManager (Android)
Differential Revision: D45866244 fbshipit-source-id: 90769b04f0e7dfede0e7df0482fe119c4601e4f0
1 parent dd716e8 commit 1e6f79d

File tree

21 files changed

+188
-6
lines changed

21 files changed

+188
-6
lines changed

packages/react-native/React/Fabric/RCTScheduler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ NS_ASSUME_NONNULL_BEGIN
6767

6868
- (void)animationTick;
6969

70+
- (void)reportMount:(facebook::react::SurfaceId)surfaceId;
71+
7072
- (void)addEventListener:(std::shared_ptr<facebook::react::EventListener> const &)listener;
7173

7274
- (void)removeEventListener:(std::shared_ptr<facebook::react::EventListener> const &)listener;

packages/react-native/React/Fabric/RCTScheduler.mm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@ - (void)animationTick
132132
_scheduler->animationTick();
133133
}
134134

135+
- (void)reportMount:(facebook::react::SurfaceId)surfaceId
136+
{
137+
_scheduler->reportMount(surfaceId);
138+
}
139+
135140
- (void)dealloc
136141
{
137142
if (_animationDriver) {

packages/react-native/React/Fabric/RCTSurfacePresenter.mm

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,10 @@ - (RCTScheduler *)_createScheduler
280280
CoreFeatures::enableGranularScrollViewStateUpdatesIOS = true;
281281
}
282282

283+
if (reactNativeConfig && reactNativeConfig->getBool("react_fabric:enable_mount_hooks_ios")) {
284+
CoreFeatures::enableMountHooks = true;
285+
}
286+
283287
auto componentRegistryFactory =
284288
[factory = wrapManagedObject(_mountingManager.componentViewRegistry.componentViewFactory)](
285289
EventDispatcher::Weak const &eventDispatcher, ContextContainer::Shared const &contextContainer) {
@@ -442,6 +446,15 @@ - (void)mountingManager:(RCTMountingManager *)mountingManager didMountComponents
442446
[observer didMountComponentsWithRootTag:rootTag];
443447
}
444448
}
449+
450+
RCTScheduler *scheduler = [self scheduler];
451+
if (scheduler) {
452+
// Notify mount when the effects are visible and prevent mount hooks to
453+
// delay paint.
454+
dispatch_async(dispatch_get_main_queue(), ^{
455+
[scheduler reportMount:rootTag];
456+
});
457+
}
445458
}
446459

447460
- (NSArray<id<RCTSurfacePresenterObserver>> *)_getObservers

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,7 @@ public class ReactFeatureFlags {
156156
* HostObject pattern
157157
*/
158158
public static boolean useNativeState = false;
159+
160+
/** Report mount operations from the host platform to notify mount hooks. */
161+
public static boolean enableMountHooks = false;
159162
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ public void setConstraints(
5252

5353
public void driveCxxAnimations();
5454

55+
public void reportMount(int surfaceId);
56+
5557
public ReadableNativeMap getInspectorDataForInstance(EventEmitterWrapper eventEmitterWrapper);
5658

5759
public void register(

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/BindingImpl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ public native void setConstraints(
8686

8787
public native void driveCxxAnimations();
8888

89+
public native void reportMount(int surfaceId);
90+
8991
public native ReadableNativeMap getInspectorDataForInstance(
9092
EventEmitterWrapper eventEmitterWrapper);
9193

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import android.annotation.SuppressLint;
2323
import android.content.Context;
2424
import android.graphics.Point;
25+
import android.os.Handler;
26+
import android.os.Looper;
2527
import android.os.SystemClock;
2628
import android.view.View;
2729
import android.view.accessibility.AccessibilityEvent;
@@ -81,10 +83,13 @@
8183
import com.facebook.react.uimanager.events.RCTEventEmitter;
8284
import com.facebook.react.views.text.TextLayoutManager;
8385
import com.facebook.react.views.text.TextLayoutManagerMapBuffer;
86+
import java.util.ArrayList;
8487
import java.util.HashMap;
88+
import java.util.List;
8589
import java.util.Map;
8690
import java.util.Queue;
8791
import java.util.concurrent.CopyOnWriteArrayList;
92+
import java.util.concurrent.atomic.AtomicBoolean;
8893

8994
/**
9095
* We instruct ProGuard not to strip out any fields or methods, because many of these methods are
@@ -166,6 +171,9 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
166171
@NonNull
167172
private final CopyOnWriteArrayList<UIManagerListener> mListeners = new CopyOnWriteArrayList<>();
168173

174+
@NonNull private final AtomicBoolean mMountNotificationScheduled = new AtomicBoolean(false);
175+
@NonNull private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
176+
169177
@ThreadConfined(UI)
170178
@NonNull
171179
private final DispatchUIFrameCallback mDispatchUIFrameCallback;
@@ -1179,17 +1187,50 @@ public Map<String, Long> getPerformanceCounters() {
11791187

11801188
private class MountItemDispatchListener implements MountItemDispatcher.ItemDispatchListener {
11811189
@Override
1182-
public void willMountItems() {
1190+
public void willMountItems(@Nullable List<MountItem> mountItems) {
11831191
for (UIManagerListener listener : mListeners) {
11841192
listener.willMountItems(FabricUIManager.this);
11851193
}
11861194
}
11871195

11881196
@Override
1189-
public void didMountItems() {
1197+
public void didMountItems(@Nullable List<MountItem> mountItems) {
11901198
for (UIManagerListener listener : mListeners) {
11911199
listener.didMountItems(FabricUIManager.this);
11921200
}
1201+
1202+
if (!ReactFeatureFlags.enableMountHooks) {
1203+
return;
1204+
}
1205+
1206+
boolean mountNotificationScheduled = mMountNotificationScheduled.getAndSet(true);
1207+
if (!mountNotificationScheduled) {
1208+
// Notify mount when the effects are visible and prevent mount hooks to
1209+
// delay paint.
1210+
mMainThreadHandler.postAtFrontOfQueue(
1211+
new Runnable() {
1212+
@Override
1213+
public void run() {
1214+
mMountNotificationScheduled.set(false);
1215+
1216+
if (mountItems == null) {
1217+
return;
1218+
}
1219+
1220+
// Collect surface IDs for all the mount items
1221+
List<Integer> surfaceIds = new ArrayList();
1222+
for (MountItem mountItem : mountItems) {
1223+
if (!surfaceIds.contains(mountItem.getSurfaceId())) {
1224+
surfaceIds.add(mountItem.getSurfaceId());
1225+
}
1226+
}
1227+
1228+
for (int surfaceId : surfaceIds) {
1229+
mBinding.reportMount(surfaceId);
1230+
}
1231+
}
1232+
});
1233+
}
11931234
}
11941235

11951236
@Override

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountItemDispatcher.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ private boolean dispatchMountItems() {
192192
return false;
193193
}
194194

195-
mItemDispatchListener.willMountItems();
195+
mItemDispatchListener.willMountItems(mountItemsToDispatch);
196196

197197
// As an optimization, execute all ViewCommands first
198198
// This should be:
@@ -301,7 +301,7 @@ private boolean dispatchMountItems() {
301301
mBatchedExecutionTime += SystemClock.uptimeMillis() - batchedExecutionStartTime;
302302
}
303303

304-
mItemDispatchListener.didMountItems();
304+
mItemDispatchListener.didMountItems(mountItemsToDispatch);
305305

306306
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
307307

@@ -419,9 +419,9 @@ private static void printMountItem(MountItem mountItem, String prefix) {
419419
}
420420

421421
public interface ItemDispatchListener {
422-
void willMountItems();
422+
void willMountItems(List<MountItem> mountItems);
423423

424-
void didMountItems();
424+
void didMountItems(List<MountItem> mountItems);
425425

426426
void didDispatchMountItems();
427427
}

packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,15 @@ void Binding::driveCxxAnimations() {
9595
scheduler_->animationTick();
9696
}
9797

98+
void Binding::reportMount(SurfaceId surfaceId) {
99+
const auto &scheduler = getScheduler();
100+
if (!scheduler) {
101+
LOG(ERROR) << "Binding::reportMount: scheduler disappeared";
102+
return;
103+
}
104+
scheduler->reportMount(surfaceId);
105+
}
106+
98107
#pragma mark - Surface management
99108

100109
void Binding::startSurface(
@@ -565,6 +574,7 @@ void Binding::registerNatives() {
565574
makeNativeMethod("setConstraints", Binding::setConstraints),
566575
makeNativeMethod("setPixelDensity", Binding::setPixelDensity),
567576
makeNativeMethod("driveCxxAnimations", Binding::driveCxxAnimations),
577+
makeNativeMethod("reportMount", Binding::reportMount),
568578
makeNativeMethod(
569579
"uninstallFabricUIManager", Binding::uninstallFabricUIManager),
570580
makeNativeMethod("registerSurface", Binding::registerSurface),

packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ class Binding : public jni::HybridClass<Binding>,
119119
void setPixelDensity(float pointScaleFactor);
120120

121121
void driveCxxAnimations();
122+
void reportMount(SurfaceId surfaceId);
122123

123124
void uninstallFabricUIManager();
124125

0 commit comments

Comments
 (0)