Skip to content

Commit

Permalink
Move lifecycle listener inside JavaTimerManager (#43338)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #43338

Reafactor JavaTimerManager so more code is shared between bridge and bridgeless.

Note that HeadlessJSTaskContext is not currently configured when using bridgeless.

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D54496604

fbshipit-source-id: 2a61294267df372e69f8316dd8f8059625d0a2bd
  • Loading branch information
javache authored and pull[bot] committed Mar 12, 2024
1 parent 04f3dff commit 59e1fc8
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 152 deletions.
19 changes: 5 additions & 14 deletions packages/react-native/ReactAndroid/api/ReactAndroid.api
Original file line number Diff line number Diff line change
Expand Up @@ -3032,7 +3032,7 @@ public abstract interface class com/facebook/react/modules/core/JavaScriptTimerE
public abstract fun emitTimeDriftWarning (Ljava/lang/String;)V
}

public class com/facebook/react/modules/core/JavaTimerManager {
public class com/facebook/react/modules/core/JavaTimerManager : com/facebook/react/bridge/LifecycleEventListener, com/facebook/react/jstasks/HeadlessJsTaskEventListener {
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;Lcom/facebook/react/modules/core/JavaScriptTimerExecutor;Lcom/facebook/react/modules/core/ReactChoreographer;Lcom/facebook/react/devsupport/interfaces/DevSupportManager;)V
public fun createAndMaybeCallTimer (IIDZ)V
public fun createTimer (IJZ)V
Expand Down Expand Up @@ -3078,27 +3078,18 @@ public final class com/facebook/react/modules/core/ReactChoreographer$CallbackTy
public static fun values ()[Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType;
}

public final class com/facebook/react/modules/core/TimingModule : com/facebook/fbreact/specs/NativeTimingSpec, com/facebook/react/bridge/LifecycleEventListener, com/facebook/react/jstasks/HeadlessJsTaskEventListener {
public final class com/facebook/react/modules/core/TimingModule : com/facebook/fbreact/specs/NativeTimingSpec, com/facebook/react/modules/core/JavaScriptTimerExecutor {
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;Lcom/facebook/react/devsupport/interfaces/DevSupportManager;)V
public fun callIdleCallbacks (D)V
public fun callTimers (Lcom/facebook/react/bridge/WritableArray;)V
public fun createTimer (DDDZ)V
public fun deleteTimer (D)V
public fun emitTimeDriftWarning (Ljava/lang/String;)V
public fun initialize ()V
public fun invalidate ()V
public fun onHeadlessJsTaskFinish (I)V
public fun onHeadlessJsTaskStart (I)V
public fun onHostDestroy ()V
public fun onHostPause ()V
public fun onHostResume ()V
public fun setSendIdleEvents (Z)V
}

public class com/facebook/react/modules/core/TimingModule$BridgeTimerExecutor : com/facebook/react/modules/core/JavaScriptTimerExecutor {
public fun <init> (Lcom/facebook/react/modules/core/TimingModule;)V
public fun callIdleCallbacks (D)V
public fun callTimers (Lcom/facebook/react/bridge/WritableArray;)V
public fun emitTimeDriftWarning (Ljava/lang/String;)V
}

public class com/facebook/react/modules/debug/DevSettingsModule : com/facebook/fbreact/specs/NativeDevSettingsSpec {
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;Lcom/facebook/react/devsupport/interfaces/DevSupportManager;)V
public fun addListener (Ljava/lang/String;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
import androidx.annotation.Nullable;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.common.SystemClock;
import com.facebook.react.devsupport.interfaces.DevSupportManager;
import com.facebook.react.jstasks.HeadlessJsTaskContext;
import com.facebook.react.jstasks.HeadlessJsTaskEventListener;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.concurrent.atomic.AtomicBoolean;
Expand All @@ -28,7 +30,7 @@
*
* <p>This is used by the NativeModule {@link TimingModule}.
*/
public class JavaTimerManager {
public class JavaTimerManager implements LifecycleEventListener, HeadlessJsTaskEventListener {

// These timing constants should be kept in sync with the ones in `JSTimers.js`.
// The minimum time in milliseconds left in the frame to call idle callbacks.
Expand Down Expand Up @@ -196,19 +198,24 @@ public int compare(Timer lhs, Timer rhs) {
}
});
mTimerIdsToTimers = new SparseArray<>();

mReactApplicationContext.addLifecycleEventListener(this);
}

@Override
public void onHostPause() {
isPaused.set(true);
clearFrameCallback();
maybeIdleCallback();
}

@Override
public void onHostDestroy() {
clearFrameCallback();
maybeIdleCallback();
}

@Override
public void onHostResume() {
isPaused.set(false);
// TODO(5195192) Investigate possible problems related to restarting all tasks at the same
Expand All @@ -217,13 +224,15 @@ public void onHostResume() {
maybeSetChoreographerIdleCallback();
}

@Override
public void onHeadlessJsTaskStart(int taskId) {
if (!isRunningTasks.getAndSet(true)) {
setChoreographerCallback();
maybeSetChoreographerIdleCallback();
}
}

@Override
public void onHeadlessJsTaskFinish(int taskId) {
HeadlessJsTaskContext headlessJsTaskContext =
HeadlessJsTaskContext.getInstance(mReactApplicationContext);
Expand All @@ -235,6 +244,8 @@ public void onHeadlessJsTaskFinish(int taskId) {
}

public void onInstanceDestroy() {
mReactApplicationContext.removeLifecycleEventListener(this);

clearFrameCallback();
clearChoreographerIdleCallback();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,68 +8,31 @@
package com.facebook.react.modules.core;

import com.facebook.fbreact.specs.NativeTimingSpec;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.common.annotations.VisibleForTesting;
import com.facebook.react.devsupport.interfaces.DevSupportManager;
import com.facebook.react.jstasks.HeadlessJsTaskContext;
import com.facebook.react.jstasks.HeadlessJsTaskEventListener;
import com.facebook.react.module.annotations.ReactModule;

/** Native module for JS timer execution. Timers fire on frame boundaries. */
@ReactModule(name = NativeTimingSpec.NAME)
public final class TimingModule extends NativeTimingSpec
implements LifecycleEventListener, HeadlessJsTaskEventListener {

public class BridgeTimerExecutor implements JavaScriptTimerExecutor {
@Override
public void callTimers(WritableArray timerIDs) {
ReactApplicationContext reactApplicationContext = getReactApplicationContextIfActiveOrWarn();

if (reactApplicationContext != null) {
reactApplicationContext.getJSModule(JSTimers.class).callTimers(timerIDs);
}
}

@Override
public void callIdleCallbacks(double frameTime) {
ReactApplicationContext reactApplicationContext = getReactApplicationContextIfActiveOrWarn();

if (reactApplicationContext != null) {
reactApplicationContext.getJSModule(JSTimers.class).callIdleCallbacks(frameTime);
}
}

@Override
public void emitTimeDriftWarning(String warningMessage) {
ReactApplicationContext reactApplicationContext = getReactApplicationContextIfActiveOrWarn();

if (reactApplicationContext != null) {
reactApplicationContext.getJSModule(JSTimers.class).emitTimeDriftWarning(warningMessage);
}
}
}

public final class TimingModule extends NativeTimingSpec implements JavaScriptTimerExecutor {
private final JavaTimerManager mJavaTimerManager;

public TimingModule(ReactApplicationContext reactContext, DevSupportManager devSupportManager) {
super(reactContext);

mJavaTimerManager =
new JavaTimerManager(
reactContext,
new BridgeTimerExecutor(),
ReactChoreographer.getInstance(),
devSupportManager);
reactContext, this, ReactChoreographer.getInstance(), devSupportManager);
}

@Override
public void initialize() {
getReactApplicationContext().addLifecycleEventListener(this);
HeadlessJsTaskContext headlessJsTaskContext =
HeadlessJsTaskContext.getInstance(getReactApplicationContext());
headlessJsTaskContext.addTaskEventListener(this);
headlessJsTaskContext.addTaskEventListener(mJavaTimerManager);
}

@Override
Expand Down Expand Up @@ -97,28 +60,30 @@ public void setSendIdleEvents(final boolean sendIdleEvents) {
}

@Override
public void onHostResume() {
mJavaTimerManager.onHostResume();
}
public void callTimers(WritableArray timerIDs) {
ReactApplicationContext reactApplicationContext = getReactApplicationContextIfActiveOrWarn();

@Override
public void onHostPause() {
mJavaTimerManager.onHostPause();
if (reactApplicationContext != null) {
reactApplicationContext.getJSModule(JSTimers.class).callTimers(timerIDs);
}
}

@Override
public void onHostDestroy() {
mJavaTimerManager.onHostDestroy();
}
public void callIdleCallbacks(double frameTime) {
ReactApplicationContext reactApplicationContext = getReactApplicationContextIfActiveOrWarn();

@Override
public void onHeadlessJsTaskStart(int taskId) {
mJavaTimerManager.onHeadlessJsTaskStart(taskId);
if (reactApplicationContext != null) {
reactApplicationContext.getJSModule(JSTimers.class).callIdleCallbacks(frameTime);
}
}

@Override
public void onHeadlessJsTaskFinish(int taskId) {
mJavaTimerManager.onHeadlessJsTaskFinish(taskId);
public void emitTimeDriftWarning(String warningMessage) {
ReactApplicationContext reactApplicationContext = getReactApplicationContextIfActiveOrWarn();

if (reactApplicationContext != null) {
reactApplicationContext.getJSModule(JSTimers.class).emitTimeDriftWarning(warningMessage);
}
}

@Override
Expand All @@ -127,9 +92,9 @@ public void invalidate() {

HeadlessJsTaskContext headlessJsTaskContext =
HeadlessJsTaskContext.getInstance(reactApplicationContext);
headlessJsTaskContext.removeTaskEventListener(this);
headlessJsTaskContext.removeTaskEventListener(mJavaTimerManager);

mJavaTimerManager.onInstanceDestroy();
reactApplicationContext.removeLifecycleEventListener(this);
}

@VisibleForTesting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import com.facebook.react.bridge.JSBundleLoader;
import com.facebook.react.bridge.JSBundleLoaderDelegate;
import com.facebook.react.bridge.JavaScriptContextHolder;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.NativeArray;
import com.facebook.react.bridge.NativeMap;
import com.facebook.react.bridge.NativeModule;
Expand Down Expand Up @@ -143,6 +142,7 @@ final class ReactInstance {
if (useDevSupport) {
devSupportManager.startInspector();
}

JSTimerExecutor jsTimerExecutor = createJSTimerExecutor();
mJavaTimerManager =
new JavaTimerManager(
Expand All @@ -151,24 +151,6 @@ final class ReactInstance {
ReactChoreographer.getInstance(),
devSupportManager);

mBridgelessReactContext.addLifecycleEventListener(
new LifecycleEventListener() {
@Override
public void onHostResume() {
mJavaTimerManager.onHostResume();
}

@Override
public void onHostPause() {
mJavaTimerManager.onHostPause();
}

@Override
public void onHostDestroy() {
mJavaTimerManager.onHostDestroy();
}
});

JSRuntimeFactory jsRuntimeFactory = mDelegate.getJsRuntimeFactory();
BindingsInstaller bindingsInstaller = mDelegate.getBindingsInstaller();
// Notify JS if profiling is enabled
Expand Down Expand Up @@ -448,6 +430,7 @@ public Collection<NativeModule> getNativeModules() {
mQueueConfiguration.destroy();
mTurboModuleManager.invalidate();
mFabricUIManager.invalidate();
mJavaTimerManager.onInstanceDestroy();
mHybridData.resetNative();
mComponentNameResolverManager = null;
mUIConstantsProviderManager = null;
Expand Down
Loading

0 comments on commit 59e1fc8

Please sign in to comment.