Skip to content

Commit cb105c5

Browse files
rshestfacebook-github-bot
authored andcommitted
Convert modules/core/ReactChoreographer to Kotlin
Differential Revision: D60445731
1 parent d1f63ee commit cb105c5

File tree

5 files changed

+167
-195
lines changed

5 files changed

+167
-195
lines changed

packages/react-native/ReactAndroid/api/ReactAndroid.api

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3128,7 +3128,7 @@ public abstract interface class com/facebook/react/modules/common/ModuleDataClea
31283128
public abstract fun clearSensitiveData ()V
31293129
}
31303130

3131-
public class com/facebook/react/modules/core/ChoreographerCompat {
3131+
public final class com/facebook/react/modules/core/ChoreographerCompat {
31323132
public fun <init> ()V
31333133
}
31343134

@@ -3208,10 +3208,12 @@ public abstract interface class com/facebook/react/modules/core/RCTNativeAppEven
32083208
}
32093209

32103210
public final class com/facebook/react/modules/core/ReactChoreographer {
3211-
public static fun getInstance ()Lcom/facebook/react/modules/core/ReactChoreographer;
3212-
public static fun initialize (Lcom/facebook/react/internal/ChoreographerProvider;)V
3213-
public fun postFrameCallback (Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType;Landroid/view/Choreographer$FrameCallback;)V
3214-
public fun removeFrameCallback (Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType;Landroid/view/Choreographer$FrameCallback;)V
3211+
public static final field Companion Lcom/facebook/react/modules/core/ReactChoreographer$Companion;
3212+
public synthetic fun <init> (Lcom/facebook/react/internal/ChoreographerProvider;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
3213+
public static final fun getInstance ()Lcom/facebook/react/modules/core/ReactChoreographer;
3214+
public static final fun initialize (Lcom/facebook/react/internal/ChoreographerProvider;)V
3215+
public final fun postFrameCallback (Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType;Landroid/view/Choreographer$FrameCallback;)V
3216+
public final fun removeFrameCallback (Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType;Landroid/view/Choreographer$FrameCallback;)V
32153217
}
32163218

32173219
public final class com/facebook/react/modules/core/ReactChoreographer$CallbackType : java/lang/Enum {
@@ -3220,10 +3222,16 @@ public final class com/facebook/react/modules/core/ReactChoreographer$CallbackTy
32203222
public static final field NATIVE_ANIMATED_MODULE Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType;
32213223
public static final field PERF_MARKERS Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType;
32223224
public static final field TIMERS_EVENTS Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType;
3225+
public static fun getEntries ()Lkotlin/enums/EnumEntries;
32233226
public static fun valueOf (Ljava/lang/String;)Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType;
32243227
public static fun values ()[Lcom/facebook/react/modules/core/ReactChoreographer$CallbackType;
32253228
}
32263229

3230+
public final class com/facebook/react/modules/core/ReactChoreographer$Companion {
3231+
public final fun getInstance ()Lcom/facebook/react/modules/core/ReactChoreographer;
3232+
public final fun initialize (Lcom/facebook/react/internal/ChoreographerProvider;)V
3233+
}
3234+
32273235
public final class com/facebook/react/modules/core/TimingModule : com/facebook/fbreact/specs/NativeTimingSpec, com/facebook/react/modules/core/JavaScriptTimerExecutor {
32283236
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;Lcom/facebook/react/devsupport/interfaces/DevSupportManager;)V
32293237
public fun callIdleCallbacks (D)V

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/ChoreographerCompat.java

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.modules.core
9+
10+
import android.view.Choreographer
11+
12+
public class ChoreographerCompat {
13+
14+
@Deprecated("Use Choreographer.FrameCallback instead")
15+
public abstract class FrameCallback : Choreographer.FrameCallback
16+
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java

Lines changed: 0 additions & 172 deletions
This file was deleted.
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.modules.core
9+
10+
import android.view.Choreographer
11+
import com.facebook.common.logging.FLog
12+
import com.facebook.infer.annotation.Assertions
13+
import com.facebook.react.bridge.UiThreadUtil
14+
import com.facebook.react.common.ReactConstants
15+
import com.facebook.react.internal.ChoreographerProvider
16+
import java.util.ArrayDeque
17+
18+
/**
19+
* A simple wrapper around Choreographer that allows us to control the order certain callbacks are
20+
* executed within a given frame. The wrapped Choreographer instance will always be the main thread
21+
* one and the API's are safe to use from any thread.
22+
*/
23+
public class ReactChoreographer private constructor(choreographerProvider: ChoreographerProvider) {
24+
public enum class CallbackType(internal val order: Int) {
25+
/** For use by perf markers that need to happen immediately after draw */
26+
PERF_MARKERS(0),
27+
/** For use by [com.facebook.react.uimanager.UIManagerModule] */
28+
DISPATCH_UI(1),
29+
/** For use by [com.facebook.react.animated.NativeAnimatedModule] */
30+
NATIVE_ANIMATED_MODULE(2),
31+
/** Events that make JS do things. */
32+
TIMERS_EVENTS(3),
33+
/**
34+
* Event used to trigger the idle callback. Called after all UI work has been dispatched to JS.
35+
*/
36+
IDLE_EVENT(4)
37+
}
38+
39+
private var choreographer: ChoreographerProvider.Choreographer? = null
40+
private val callbackQueues: Array<ArrayDeque<Choreographer.FrameCallback>> =
41+
Array(CallbackType.entries.size) { ArrayDeque() }
42+
private var totalCallbacks = 0
43+
private var hasPostedCallback = false
44+
45+
private val frameCallback =
46+
Choreographer.FrameCallback { frameTimeNanos ->
47+
synchronized(callbackQueues) {
48+
49+
// Callbacks run once and are then automatically removed, the callback will
50+
// be posted again from postFrameCallback
51+
hasPostedCallback = false
52+
for (i in callbackQueues.indices) {
53+
val callbackQueue = callbackQueues[i]
54+
val initialLength = callbackQueue.size
55+
for (callback in 0 until initialLength) {
56+
val frameCallback = callbackQueue.pollFirst()
57+
if (frameCallback != null) {
58+
frameCallback.doFrame(frameTimeNanos)
59+
totalCallbacks--
60+
} else {
61+
FLog.e(ReactConstants.TAG, "Tried to execute non-existent frame callback")
62+
}
63+
}
64+
}
65+
maybeRemoveFrameCallback()
66+
}
67+
}
68+
69+
init {
70+
UiThreadUtil.runOnUiThread { choreographer = choreographerProvider.getChoreographer() }
71+
}
72+
73+
public fun postFrameCallback(type: CallbackType, callback: Choreographer.FrameCallback) {
74+
synchronized(callbackQueues) {
75+
callbackQueues[type.order].addLast(callback)
76+
totalCallbacks++
77+
Assertions.assertCondition(totalCallbacks > 0)
78+
if (!hasPostedCallback) {
79+
if (choreographer == null) {
80+
// Schedule on the main thread, at which point the constructor's async work will have
81+
// completed
82+
UiThreadUtil.runOnUiThread {
83+
synchronized(callbackQueues) { postFrameCallbackOnChoreographer() }
84+
}
85+
} else {
86+
postFrameCallbackOnChoreographer()
87+
}
88+
}
89+
}
90+
}
91+
92+
/**
93+
* This method writes on mHasPostedCallback and it should be called from another method that has
94+
* the lock on [callbackQueues].
95+
*/
96+
private fun postFrameCallbackOnChoreographer() {
97+
choreographer?.postFrameCallback(frameCallback)
98+
hasPostedCallback = true
99+
}
100+
101+
public fun removeFrameCallback(type: CallbackType, frameCallback: Choreographer.FrameCallback?) {
102+
synchronized(callbackQueues) {
103+
if (callbackQueues[type.order].removeFirstOccurrence(frameCallback)) {
104+
totalCallbacks--
105+
maybeRemoveFrameCallback()
106+
} else {
107+
FLog.e(ReactConstants.TAG, "Tried to remove non-existent frame callback")
108+
}
109+
}
110+
}
111+
112+
/**
113+
* This method reads and writes on mHasPostedCallback and it should be called from another method
114+
* that already has the lock on [callbackQueues].
115+
*/
116+
private fun maybeRemoveFrameCallback() {
117+
Assertions.assertCondition(totalCallbacks >= 0)
118+
if (totalCallbacks == 0 && hasPostedCallback) {
119+
choreographer?.removeFrameCallback(frameCallback)
120+
hasPostedCallback = false
121+
}
122+
}
123+
124+
public companion object {
125+
private var choreographer: ReactChoreographer? = null
126+
127+
@JvmStatic
128+
public fun initialize(choreographerProvider: ChoreographerProvider) {
129+
if (choreographer == null) {
130+
choreographer = ReactChoreographer(choreographerProvider)
131+
}
132+
}
133+
134+
@JvmStatic
135+
public val instance: ReactChoreographer
136+
get() = checkNotNull(choreographer) { "ReactChoreographer needs to be initialized." }
137+
}
138+
}

0 commit comments

Comments
 (0)