Repository navigation
Commit 98291bc
Look up Android image resources without throwing an exception (#59456)
Summary:
In Release builds on Android, an image from the bundle (`<Image source={require('./icon.png')} />`) is a drawable resource, and its source is the resource name, for example `assets_icon`. `ImageSource` turns that name into a URI with `ResourceDrawableIdHelper.getResourceDrawableId`. The same lookup runs for `defaultSource` and `loadingIndicatorSource`, `Image.getSize` of a bundled image, and TextInput's `inlineImageLeft`. Images loaded from Metro or from a bundle outside the APK have a URI scheme and don't use it.
**Current behavior.** `getResourceDrawableId` first tries the name as a numeric resource id with `toInt()` and catches the `NumberFormatException`. Resource names are not numbers, so every such image source throws an exception and fills in a stack trace as deep as the mount call stack. This happens before the cache of looked-up names, so names that were already looked up throw too. On a Samsung Galaxy A14 the lookup takes about 0.24 ms for each image source, almost all of it in the exception.
**With this change.** The name is parsed with `toIntOrNull()`, which accepts the same numbers as `toInt()` and returns `null` instead of throwing. Numeric names still return the same id, and other names are still looked up as drawables, so every name gives the same result as before.
## Changelog:
[ANDROID] [CHANGED] - Images from the app bundle look up their resource without throwing an exception
Pull Request resolved: #59456
Test Plan:
- The pinned ktfmt (`--dry-run --set-exit-if-changed`) passes on both files.
- Added `ResourceDrawableIdHelperTest` (5 tests: empty name, numeric names, a name looked up as a drawable after normalization, a number too big for an `Int`, an unknown name). It passes with this change and with the old code, so the results are the same.
- **Device:** Samsung Galaxy A14 (SM-A145R, Android 15), RNTester built with Gradle in Release (`assembleRelease`, arm64-v8a) and compiled with `cmd package compile -m speed`. The scenario is a local Playground screen, not part of this PR: a long feed with avatars and photos from the bundle that scrolls by itself.
- **A/B setup:** a single APK with a local switch (an `adb shell setprop`, not part of this PR) that runs either the old `toInt()` with `try`/`catch` or `toIntOrNull()`, and times every call. Launches alternate A B B A A B B A, 4 per arm. Every launch made 1,300 lookups.
| | before | this PR | change |
|---|--:|--:|--:|
| Time per `getResourceDrawableId` | 239–243 µs | 16.4–17.3 µs | −93% |
- **Perfetto** (30 s of the same feed): `ReactImageManager.setSource` went from 3.5% to 1.6% of the main thread's samples, and the samples in exception handling under it from 237 to 0.
- **Rendering:** screenshots of the feed in both arms are byte-identical.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Reviewed By: javache
Differential Revision: D127722121
Pulled By: Abbondanzo
fbshipit-source-id: 3fadd8cfe62f335ffcfd917f903e51ef940082c71 parent ed15270 commit 98291bc
2 files changed
Lines changed: 79 additions & 5 deletions
File tree
- packages/react-native/ReactAndroid/src
- main/java/com/facebook/react/views/imagehelper
- test/java/com/facebook/react/views/imagehelper
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
34 | | - | |
35 | | - | |
36 | | - | |
37 | | - | |
38 | | - | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
39 | 38 | | |
40 | 39 | | |
41 | 40 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
0 commit comments