Skip to content

Commit b2ffd34

Browse files
l2hyunwoofacebook-github-bot
authored andcommitted
Refactor ReactAndroid to use buildReadableMap, buildReadableArray DSL (facebook#51145)
Summary: This PR refactors the entire ReactAndroid package to replace manual `Arguments.createMap()…` and `Arguments.createArray()…` calls with the new Kotlin DSL helpers `buildReadableMap { … }` and `buildReadableArray { … }`. All eligible call sites have been migrated to the DSL, except in functions whose signatures explicitly declare or return WritableMap or WritableArray. No runtime behavior changes are introduced; existing functionality and tests continue to pass unchanged. ## Changelog: <!-- Help reviewers and the release process by writing your own changelog entry. Pick one each for the category and type tags: [ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message For more details, see: https://reactnative.dev/contributing/changelogs-in-pull-requests --> [ANDROID] [CHANGED] Apply Collections DSL on ReactAndroid package Pull Request resolved: facebook#51145 Test Plan: ``` yarn android yarn test-android ``` Reviewed By: rshest Differential Revision: D74401357 Pulled By: cortinico fbshipit-source-id: 0f7b7dfbb7b495675bc4730bdf018666e9041884
1 parent d362e49 commit b2ffd34

File tree

19 files changed

+289
-235
lines changed

19 files changed

+289
-235
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,6 +1353,8 @@ public final class com/facebook/react/bridge/ReadableArrayBuilder {
13531353
public final fun add (D)V
13541354
public final fun add (I)V
13551355
public final fun add (J)V
1356+
public final fun add (Lcom/facebook/react/bridge/ReadableArray;)V
1357+
public final fun add (Lcom/facebook/react/bridge/ReadableMap;)V
13561358
public final fun add (Ljava/lang/String;)V
13571359
public final fun add (Z)V
13581360
public final fun addArray (Lkotlin/jvm/functions/Function1;)V
@@ -1386,6 +1388,8 @@ public final class com/facebook/react/bridge/ReadableMapBuilder {
13861388
public final fun put (Ljava/lang/String;D)V
13871389
public final fun put (Ljava/lang/String;I)V
13881390
public final fun put (Ljava/lang/String;J)V
1391+
public final fun put (Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;)V
1392+
public final fun put (Ljava/lang/String;Lcom/facebook/react/bridge/ReadableMap;)V
13891393
public final fun put (Ljava/lang/String;Ljava/lang/String;)V
13901394
public final fun put (Ljava/lang/String;Z)V
13911395
public final fun putArray (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.kt

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import androidx.annotation.AnyThread
1111
import androidx.annotation.UiThread
1212
import com.facebook.common.logging.FLog
1313
import com.facebook.fbreact.specs.NativeAnimatedModuleSpec
14-
import com.facebook.react.bridge.Arguments
1514
import com.facebook.react.bridge.Callback
1615
import com.facebook.react.bridge.LifecycleEventListener
1716
import com.facebook.react.bridge.ReactApplicationContext
@@ -20,6 +19,7 @@ import com.facebook.react.bridge.ReadableArray
2019
import com.facebook.react.bridge.ReadableMap
2120
import com.facebook.react.bridge.UIManager
2221
import com.facebook.react.bridge.UIManagerListener
22+
import com.facebook.react.bridge.buildReadableMap
2323
import com.facebook.react.common.annotations.UnstableReactNativeAPI
2424
import com.facebook.react.common.annotations.VisibleForTesting
2525
import com.facebook.react.common.build.ReactBuildConfig
@@ -230,14 +230,8 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext?) :
230230
return
231231
}
232232

233-
val tagsArray = Arguments.createArray()
234-
for (tag in tags) {
235-
tagsArray.pushInt(tag)
236-
}
237-
238233
// emit the event to JS to resync the trees
239-
val onAnimationEndedData = Arguments.createMap()
240-
onAnimationEndedData.putArray("tags", tagsArray)
234+
val onAnimationEndedData = buildReadableMap { putArray("tags") { tags.forEach { add(it) } } }
241235

242236
val reactApplicationContext = reactApplicationContextIfActiveOrWarn
243237
reactApplicationContext?.emitDeviceEvent("onUserDrivenAnimationEnded", onAnimationEndedData)
@@ -543,10 +537,11 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext?) :
543537
}
544538

545539
val listener = AnimatedNodeValueListener { value, offset ->
546-
val onAnimatedValueData = Arguments.createMap()
547-
onAnimatedValueData.putInt("tag", tag)
548-
onAnimatedValueData.putDouble("value", value)
549-
onAnimatedValueData.putDouble("offset", offset)
540+
val onAnimatedValueData = buildReadableMap {
541+
put("tag", tag)
542+
put("value", value)
543+
put("offset", offset)
544+
}
550545

551546
val reactApplicationContext = reactApplicationContextIfActiveOrWarn
552547
reactApplicationContext?.emitDeviceEvent("onAnimatedValueUpdate", onAnimatedValueData)
@@ -978,10 +973,11 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext?) :
978973
BatchExecutionOpCodes.OP_START_LISTENING_TO_ANIMATED_NODE_VALUE -> {
979974
val tag = opsAndArgs.getInt(i++)
980975
val listener = AnimatedNodeValueListener { value, offset ->
981-
val onAnimatedValueData = Arguments.createMap()
982-
onAnimatedValueData.putInt("tag", tag)
983-
onAnimatedValueData.putDouble("value", value)
984-
onAnimatedValueData.putDouble("offset", offset)
976+
val onAnimatedValueData = buildReadableMap {
977+
put("tag", tag)
978+
put("value", value)
979+
put("offset", offset)
980+
}
985981

986982
val reactApplicationContext = reactApplicationContextIfActiveOrWarn
987983
reactApplicationContext?.emitDeviceEvent(

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.kt

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import com.facebook.react.bridge.ReactSoftExceptionLogger
2020
import com.facebook.react.bridge.ReadableMap
2121
import com.facebook.react.bridge.UiThreadUtil
2222
import com.facebook.react.bridge.WritableArray
23+
import com.facebook.react.bridge.buildReadableMap
2324
import com.facebook.react.uimanager.UIManagerHelper
2425
import com.facebook.react.uimanager.common.UIManagerType
2526
import com.facebook.react.uimanager.events.Event
@@ -269,20 +270,22 @@ public class NativeAnimatedNodesManager(
269270
val animatedValueNonnull = checkNotNull(animation.animatedValue)
270271
if (animation.endCallback != null) {
271272
// Invoke animation end callback with {finished: false}
272-
val endCallbackResponse = Arguments.createMap()
273-
endCallbackResponse.putBoolean("finished", false)
274-
endCallbackResponse.putDouble("value", animatedValueNonnull.nodeValue)
275-
endCallbackResponse.putDouble("offset", animatedValueNonnull.offset)
273+
val endCallbackResponse = buildReadableMap {
274+
put("finished", false)
275+
put("value", animatedValueNonnull.nodeValue)
276+
put("offset", animatedValueNonnull.offset)
277+
}
276278
animation.endCallback?.invoke(endCallbackResponse)
277279
} else if (reactApplicationContext != null) {
278280
// If no callback is passed in, this /may/ be an animation set up by the single-op
279281
// instruction from JS, meaning that no jsi::functions are passed into native and
280282
// we communicate via RCTDeviceEventEmitter instead of callbacks.
281-
val params = Arguments.createMap()
282-
params.putInt("animationId", animation.id)
283-
params.putBoolean("finished", false)
284-
params.putDouble("value", animatedValueNonnull.nodeValue)
285-
params.putDouble("offset", animatedValueNonnull.offset)
283+
val params = buildReadableMap {
284+
put("animationId", animation.id)
285+
put("finished", false)
286+
put("value", animatedValueNonnull.nodeValue)
287+
put("offset", animatedValueNonnull.offset)
288+
}
286289
events = events ?: Arguments.createArray()
287290
events.pushMap(params)
288291
}
@@ -308,20 +311,22 @@ public class NativeAnimatedNodesManager(
308311
if (animation.id == animationId) {
309312
if (animation.endCallback != null) {
310313
// Invoke animation end callback with {finished: false}
311-
val endCallbackResponse = Arguments.createMap()
312-
endCallbackResponse.putBoolean("finished", false)
313-
endCallbackResponse.putDouble("value", checkNotNull(animation.animatedValue).nodeValue)
314-
endCallbackResponse.putDouble("offset", checkNotNull(animation.animatedValue).offset)
314+
val endCallbackResponse = buildReadableMap {
315+
put("finished", false)
316+
put("value", checkNotNull(animation.animatedValue).nodeValue)
317+
put("offset", checkNotNull(animation.animatedValue).offset)
318+
}
315319
checkNotNull(animation.endCallback).invoke(endCallbackResponse)
316320
} else if (reactApplicationContext != null) {
317321
// If no callback is passed in, this /may/ be an animation set up by the single-op
318322
// instruction from JS, meaning that no jsi::functions are passed into native and
319323
// we communicate via RCTDeviceEventEmitter instead of callbacks.
320-
val params = Arguments.createMap()
321-
params.putInt("animationId", animation.id)
322-
params.putBoolean("finished", false)
323-
params.putDouble("value", checkNotNull(animation.animatedValue).nodeValue)
324-
params.putDouble("offset", checkNotNull(animation.animatedValue).offset)
324+
val params = buildReadableMap {
325+
put("animationId", animation.id)
326+
put("finished", false)
327+
put("value", checkNotNull(animation.animatedValue).nodeValue)
328+
put("offset", checkNotNull(animation.animatedValue).offset)
329+
}
325330
events = events ?: Arguments.createArray()
326331
events.pushMap(params)
327332
}
@@ -425,9 +430,10 @@ public class NativeAnimatedNodesManager(
425430
if (reactApplicationContext == null) {
426431
return
427432
}
428-
val params = Arguments.createMap()
429-
params.putInt("tag", tag)
430-
params.putDouble("value", value)
433+
val params = buildReadableMap {
434+
put("tag", tag)
435+
put("value", value)
436+
}
431437
reactApplicationContext.emitDeviceEvent("onNativeAnimatedModuleGetValue", params)
432438
}
433439

@@ -579,20 +585,22 @@ public class NativeAnimatedNodesManager(
579585
if (animation.hasFinished) {
580586
val animatedValueNonnull = checkNotNull(animation.animatedValue)
581587
if (animation.endCallback != null) {
582-
val endCallbackResponse = Arguments.createMap()
583-
endCallbackResponse.putBoolean("finished", true)
584-
endCallbackResponse.putDouble("value", animatedValueNonnull.nodeValue)
585-
endCallbackResponse.putDouble("offset", animatedValueNonnull.offset)
588+
val endCallbackResponse = buildReadableMap {
589+
put("finished", true)
590+
put("value", animatedValueNonnull.nodeValue)
591+
put("offset", animatedValueNonnull.offset)
592+
}
586593
animation.endCallback?.invoke(endCallbackResponse)
587594
} else if (reactApplicationContext != null) {
588595
// If no callback is passed in, this /may/ be an animation set up by the single-op
589596
// instruction from JS, meaning that no jsi::functions are passed into native and
590597
// we communicate via RCTDeviceEventEmitter instead of callbacks.
591-
val params = Arguments.createMap()
592-
params.putInt("animationId", animation.id)
593-
params.putBoolean("finished", true)
594-
params.putDouble("value", animatedValueNonnull.nodeValue)
595-
params.putDouble("offset", animatedValueNonnull.offset)
598+
val params = buildReadableMap {
599+
put("animationId", animation.id)
600+
put("finished", true)
601+
put("value", animatedValueNonnull.nodeValue)
602+
put("offset", animatedValueNonnull.offset)
603+
}
596604
events = events ?: Arguments.createArray()
597605
events.pushMap(params)
598606
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/JSONArguments.kt

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -31,27 +31,28 @@ public object JSONArguments {
3131
@JvmStatic
3232
@Throws(JSONException::class)
3333
public fun fromJSONObject(obj: JSONObject): ReadableMap {
34-
val result: WritableMap = Arguments.createMap()
3534
val keys = obj.keys()
3635

37-
while (keys.hasNext()) {
38-
val key = keys.next()
39-
val value = obj.get(key)
36+
val result = buildReadableMap {
37+
while (keys.hasNext()) {
38+
val key = keys.next()
39+
val value = obj.get(key)
4040

41-
when (value) {
42-
is JSONObject -> result.putMap(key, fromJSONObject(value))
43-
is JSONArray -> result.putArray(key, fromJSONArray(value))
44-
is String -> result.putString(key, value)
45-
is Boolean -> result.putBoolean(key, value)
46-
is Int -> result.putInt(key, value)
47-
is Double -> result.putDouble(key, value)
48-
is Long -> result.putInt(key, value.toInt())
49-
else ->
50-
if (obj.isNull(key)) {
51-
result.putNull(key)
52-
} else {
53-
throw JSONException("Unexpected value when parsing JSON object. key: $key")
54-
}
41+
when (value) {
42+
is JSONObject -> put(key, fromJSONObject(value))
43+
is JSONArray -> put(key, fromJSONArray(value))
44+
is String -> put(key, value)
45+
is Boolean -> put(key, value)
46+
is Int -> put(key, value)
47+
is Double -> put(key, value)
48+
is Long -> put(key, value.toInt())
49+
else ->
50+
if (obj.isNull(key)) {
51+
putNull(key)
52+
} else {
53+
throw JSONException("Unexpected value when parsing JSON object. key: $key")
54+
}
55+
}
5556
}
5657
}
5758

@@ -79,25 +80,25 @@ public object JSONArguments {
7980
@JvmStatic
8081
@Throws(JSONException::class)
8182
public fun fromJSONArray(arr: JSONArray): ReadableArray {
82-
val result: WritableArray = Arguments.createArray()
83+
val result = buildReadableArray {
84+
repeat(arr.length()) {
85+
val value = arr.get(it)
8386

84-
for (i in 0 until arr.length()) {
85-
val value = arr.get(i)
86-
87-
when (value) {
88-
is JSONObject -> result.pushMap(fromJSONObject(value))
89-
is JSONArray -> result.pushArray(fromJSONArray(value))
90-
is String -> result.pushString(value)
91-
is Boolean -> result.pushBoolean(value)
92-
is Int -> result.pushInt(value)
93-
is Double -> result.pushDouble(value)
94-
is Long -> result.pushInt(value.toInt())
95-
else ->
96-
if (arr.isNull(i)) {
97-
result.pushNull()
98-
} else {
99-
throw JSONException("Unexpected value when parsing JSON array. index: $i")
100-
}
87+
when (value) {
88+
is JSONObject -> add(fromJSONObject(value))
89+
is JSONArray -> add(fromJSONArray(value))
90+
is String -> add(value)
91+
is Boolean -> add(value)
92+
is Int -> add(value)
93+
is Double -> add(value)
94+
is Long -> add(value.toInt())
95+
else ->
96+
if (arr.isNull(it)) {
97+
addNull()
98+
} else {
99+
throw JSONException("Unexpected value when parsing JSON array. index: $it")
100+
}
101+
}
101102
}
102103
}
103104

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableArrayBuilder.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ public class ReadableArrayBuilder(private val array: WritableArray) {
4747
array.pushDouble(value.toDouble())
4848
}
4949

50+
public fun add(value: ReadableMap) {
51+
array.pushMap(value)
52+
}
53+
54+
public fun add(value: ReadableArray) {
55+
array.pushArray(value)
56+
}
57+
5058
public fun addNull() {
5159
array.pushNull()
5260
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableMapBuilder.kt

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,19 @@ package com.facebook.react.bridge
1111
* Convenience class for building a [ReadableMap] in a Kotlin idiomatic way. You can use it as
1212
* follows:
1313
* ```
14-
* val array: ReadableArray = buildReadableArray {
15-
* add("one")
16-
* add(2)
17-
* add(true)
18-
* addNull()
19-
* addMap { put("nestedKey", "nestedValue") }
20-
* }
14+
* val map: ReadableMap = buildReadableMap {
15+
* put("first", "one")
16+
* put("second", 2)
17+
* put("third", true)
18+
* putNull("fourth")
19+
* putMap("fifth") {
20+
* put("nestedKey", "nestedValue")
21+
* }
22+
* putArray("sixth") {
23+
* add(1)
24+
* add("2")
25+
* }
26+
* }
2127
* ```
2228
*/
2329
public inline fun buildReadableMap(builder: ReadableMapBuilder.() -> Unit): ReadableMap {
@@ -51,6 +57,14 @@ public class ReadableMapBuilder(private val map: WritableMap) {
5157
map.putNull(key)
5258
}
5359

60+
public fun put(key: String, value: ReadableMap) {
61+
map.putMap(key, value)
62+
}
63+
64+
public fun put(key: String, value: ReadableArray) {
65+
map.putArray(key, value)
66+
}
67+
5468
public fun putMap(key: String, builder: ReadableMapBuilder.() -> Unit) {
5569
map.putMap(key, buildReadableMap(builder))
5670
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/AppearanceModule.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import android.content.Context
1111
import android.content.res.Configuration
1212
import androidx.appcompat.app.AppCompatDelegate
1313
import com.facebook.fbreact.specs.NativeAppearanceSpec
14-
import com.facebook.react.bridge.Arguments
1514
import com.facebook.react.bridge.ReactApplicationContext
1615
import com.facebook.react.bridge.UiThreadUtil
16+
import com.facebook.react.bridge.buildReadableMap
1717
import com.facebook.react.module.annotations.ReactModule
1818

1919
/** Module that exposes the user's preferred color scheme. */
@@ -89,8 +89,7 @@ constructor(
8989

9090
/** Sends an event to the JS instance that the preferred color scheme has changed. */
9191
public fun emitAppearanceChanged(colorScheme: String) {
92-
val appearancePreferences = Arguments.createMap()
93-
appearancePreferences.putString("colorScheme", colorScheme)
92+
val appearancePreferences = buildReadableMap { put("colorScheme", colorScheme) }
9493
val reactApplicationContext = getReactApplicationContextIfActiveOrWarn()
9594
reactApplicationContext?.emitDeviceEvent(APPEARANCE_CHANGED_EVENT_NAME, appearancePreferences)
9695
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import com.facebook.react.bridge.ReactApplicationContext
1919
import com.facebook.react.bridge.ReadableArray
2020
import com.facebook.react.bridge.ReadableMap
2121
import com.facebook.react.bridge.WritableMap
22+
import com.facebook.react.bridge.buildReadableMap
2223
import com.facebook.react.module.annotations.ReactModule
2324
import com.facebook.react.modules.network.NetworkingModule
2425
import com.facebook.react.modules.websocket.WebSocketModule
@@ -52,10 +53,11 @@ public class BlobModule(reactContext: ReactApplicationContext) :
5253
override fun onMessage(byteString: ByteString, params: WritableMap) {
5354
val data = byteString.toByteArray()
5455

55-
val blob = Arguments.createMap()
56-
blob.putString("blobId", store(data))
57-
blob.putInt("offset", 0)
58-
blob.putInt("size", data.size)
56+
val blob = buildReadableMap {
57+
put("blobId", store(data))
58+
put("offset", 0)
59+
put("size", data.size)
60+
}
5961

6062
params.putMap("data", blob)
6163
params.putString("type", "blob")

0 commit comments

Comments
 (0)