[Android][Fabric] A decoded local image can miss the current frame during a long mount
维护者通常 2 天内回复
还没有人认领这个 Issue。
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 38/100
- Issue 类型
- 缺陷
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- android, react-native
- 领域
- mobile, performance
调研方向
Start by tracing the named delivery path from AbstractDraweeController.submitRequest through DataSource.subscribe to SettableDraweeHierarchy.setImage, then reproduce on Android with the linked RNTester example. Compare a cold-cache miss with the synchronous cache-hit case while Fabric is mounting. Done means a result ready before drawing appears in that frame rather than a later one.
由索引模型根据 Issue 内容生成。
描述
Description
On Android with Fabric, a local Image that misses Fresco's bitmap memory cache can be drawn with its placeholder even when its decoded result is ready before that frame is drawn. The image is applied one or more frames later.
The reproducer mounts two Image components with the same local source in one commit:
- Image A uses
cache: 'reload', which evicts that URI before requesting it. - A small but nested vote-list subtree is mounted between A and B.
- A is decoded on a background thread while the UI thread is processing the mount.
- Image B is submitted later and synchronously hits the bitmap that A has placed in the memory cache.
The first visible frame can therefore contain A's gray placeholder and B's image, even though both use the same source.
The delivery path for A is:
AbstractDraweeController.submitRequest
→ DataSource.subscribe(subscriber, uiThreadExecutor)
→ a Handler message posted to the UI thread
→ SettableDraweeHierarchy.setImage
When the result becomes ready while the UI thread is already inside a long Choreographer.doFrame, the posted message cannot run between Fabric's mount work and traversal/draw because they execute inside the same frame message. The frame is drawn with the placeholder. If another overdue frame starts before the posted result message, the delay is amplified by that frame as well.
sequenceDiagram
participant UI as UI thread
participant BG as Fresco background thread
UI->>BG: Submit A, bitmap memory-cache miss
UI->>UI: Continue Fabric mount work
BG-->>UI: Decode A, post result Handler message
UI->>UI: Submit B, bitmap memory-cache hit
UI->>UI: Draw frame with A placeholder and B image
UI->>UI: Run A result message after the frame
UI->>UI: Draw A image in a later frame
This is intermittent in applications because a bitmap memory-cache hit is delivered synchronously and avoids the problem. A miss occurs on first use, after eviction or cache trimming, and when an app clears Fresco's memory cache. The reproducer uses cache: 'reload' only to make A start cold on every run.
On React Native 0.88.0, screen recording captured the A-placeholder/B-image frame in 10 of 10 runs with the final reproducer on a Vivo V2338A running Android 16 (API 36). The measured B-to-A display delays were:
78, 67, 67, 62, 10, 75, 77, 74, 68, 75 ms
Median: approximately 71 ms. Nine of the ten runs lasted 62–78 ms.
In a production app, the same pattern occurs with a local file:// button image during the first commit of a screen and remains visible for approximately 19–60 ms.
Expected behavior: if an image result is ready before a frame is drawn, that frame should draw the image, matching the behavior of a synchronous bitmap memory-cache hit.
Steps to reproduce
-
Check out React Native
0.88-stableat99d4ed39851392b4c65fd38fe3812669cb493376. -
Replace
packages/rn-tester/js/examples/Playground/RNTesterPlayground.jswith the linked reproducer. -
Build and install the Android release variant so that the JavaScript bundle and local assets are packaged in the APK:
./gradlew --no-daemon --max-workers=1 :packages:rn-tester:android:app:assembleRelease adb install -r packages/rn-tester/android/app/build/outputs/apk/release/app-arm64-v8a-release.apk -
Open the RNTester Playground:
adb shell "am start -a android.intent.action.VIEW -d 'rntester://example/PlaygroundExample' com.facebook.react.uiapp" -
After approximately one second, observe the first frame containing A and B. A shows its gray placeholder while B already shows the same image.
-
Tap Run again to repeat.
The first commit inserts image A, four nested vote-list rows with real local images, and image B. A second commit adds 20 more rows. The list is scrollable.
React Native Version
0.88.0
Tested from 0.88-stable commit:
99d4ed39851392b4c65fd38fe3812669cb493376
The same underlying behavior was also observed on main at:
b8ec87e457c72377dab85599e1ae8c176eb242e7
Affected Platforms
Select:
Runtime - Android
Areas
Select:
Fabric - The New Renderer
Output of npx @react-native-community/cli info
The command was run from the RNTester monorepo checkout. The CLI does not infer RNTester's workspace packages or Gradle architecture setting correctly, so it reports package entries as Not Found and newArchEnabled: false. The actual RNTester Android configuration used for the reproduction has newArchEnabled=true.
System:
OS: macOS 27.0.1
CPU: (10) arm64 Apple M5
Memory: 64.22 MB / 24.00 GB
Shell:
version: 4.9.3
path: /opt/homebrew/bin/fish
Binaries:
Node:
version: 22.22.3
path: ~/.local/state/fnm_multishells/34159_1791960164938/bin/node
Yarn:
version: 1.22.22
path: ~/.local/state/fnm_multishells/34159_1791960164938/bin/yarn
npm:
version: 10.9.8
path: ~/.local/state/fnm_multishells/34159_1791960164938/bin/npm
Watchman:
version: 2026.07.27.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.16.2
path: /Users/admin/.rbenv/shims/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 27.0
- iOS 27.0
- macOS 27.0
- tvOS 27.0
- visionOS 27.0
- watchOS 27.0
Android SDK: Not Found
IDEs:
Android Studio: 2026.2 AI-262.9437.185.2621.16467767
Xcode:
version: 27.0/27A266a
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.20.1
path: /usr/bin/javac
Ruby:
version: 2.6.10
path: /usr/bin/ruby
npmPackages:
"@react-native-community/cli": Not Found
react: Not Found
react-native: Not Found
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: false
newArchEnabled: false
iOS:
hermesEnabled: true
newArchEnabled: false
Stacktrace or Logs
No crash or JavaScript error is logged.
Final RNTesterPlayground reproduction on React Native 0.88.0:
10/10 screen recordings captured A's placeholder while B already showed the image.
B-to-A display delays:
78, 67, 67, 62, 10, 75, 77, 74, 68, 75 ms
Median: approximately 71 ms; 9/10 runs lasted 62–78 ms.
MANDATORY Reproducer
https://github.com/fairysword/react-native/blob/9bc67419dfbde083cf258af46aa27f504836034c/packages/rn-tester/js/examples/Playground/RNTesterPlayground.js
Screenshots
- 主要语言
- C++
- 星标
- 127k
- 派生
- 25.5k
- 平均合并
- 3 天 18 小时
- 30 天内合并 PR
- 188
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
react/react-native 的其他 Issue
-
难度 2/5 1-3 小时 新手友好度 76/100
react/react-native#59945 ·
维护者通常 2 天内回复
-
难度 2/5 1-3 小时 新手友好度 82/100
react/react-native#59944 ·
维护者通常 2 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
react/react-native#59942 ·
维护者通常 2 天内回复
-
难度 2/5 1-3 小时 新手友好度 76/100
react/react-native#59939 ·
维护者通常 2 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
react/react-native#59929 · 1 条评论 ·
维护者通常 2 天内回复
查看 react/react-native 的全部 Issue
相似的 Issue
-
backlog
难度 2/5 1-3 小时 新手友好度 78/100
EchoTools/nevr-runtime#2385 ·
维护者通常 1 天内回复
-
type:bug
难度 2/5 1-3 小时 新手友好度 65/100
tensorflow/tflite-micro#3995 ·
维护者通常 1 天内回复
-
CPU update 1.31x未关闭speed-report
难度 1/5 1 小时以内 新手友好度 75/100
mw00/project-maya#961 · 1 条评论 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
-
not for AI lovers
难度 2/5 1-3 小时 新手友好度 76/100
维护者通常 1 天内回复