Skip to content

⚡ Bolt: Optimize Jetpack Compose color allocation in VideoSurface - #73

Open
Shangjin-Xiao wants to merge 1 commit into
mainfrom
bolt/optimize-compose-color-allocation-14064141893790037513
Open

⚡ Bolt: Optimize Jetpack Compose color allocation in VideoSurface#73
Shangjin-Xiao wants to merge 1 commit into
mainfrom
bolt/optimize-compose-color-allocation-14064141893790037513

Conversation

@Shangjin-Xiao

@Shangjin-Xiao Shangjin-Xiao commented Sep 3, 2026

Copy link
Copy Markdown
Owner

⚡ Bolt: 优化 VideoSurface 的 Compose 颜色分配性能

💡 内容 (What)

移除了 VideoSurface.kt 中对 Color.copy(alpha = ...) 使用的 remember 代码块,改为直接计算派生的颜色值。

🎯 原因 (Why)

在 Jetpack Compose 中,Color 是一个内联的 value class(底层包装了一个 ULong 基本类型)。调用 .copy() 只是一个极低成本的位运算。但是,当把这个操作放入 remember { ... } 块中时,由于 remember 依赖于泛型,会强迫将这个轻量级的 value class 装箱(Boxing)成一个堆内存对象,以便存储到 Compose 的 slot table 中。
在像 VideoSurface 这样响应高频手势(缩放、平移)导致频繁重组(Recomposition)的组件中,避免非必要的内存分配(Allocation)能显著降低垃圾回收(GC)的压力,减少因为 GC 引起的界面掉帧。

📊 影响 (Impact)

消除了由于 remember 导致的不必要的颜色对象装箱和 Compose slot table 读写开销。

🔬 测量 (Measurement)

可以通过 Android Studio 的 Memory Profiler 在频繁缩放/平移视频时观察堆内存分配情况,分配的临时对象应当有所减少。通过 ./gradlew :app:assembleDebug 和测试保证代码的正确性未受影响。


PR created automatically by Jules for task 14064141893790037513 started by @Shangjin-Xiao


Summary by cubic

Removes remember blocks around Color.copy() calls in VideoSurface so the Color value class is no longer boxed and stored in the Compose slot table. Derived colors are now computed directly on each recomposition, cutting unnecessary memory allocation with no behavioral change.

Written for commit 4a43620. Summary will update on new commits.

Review in cubic

- Extract statically derived `Color.copy(alpha = ...)` calculations out of `remember` blocks in `VideoSurface.kt`.
- `Color` is a value class in Compose. Applying `remember` forces boxing of the primitive into an object to be stored in the Compose slot table, causing unnecessary memory allocation and overhead.
- Deriving it directly is just lightweight bitwise math.

Co-authored-by: Shangjin-Xiao <84136399+Shangjin-Xiao@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: a6dd4f35-a339-486b-82f6-8c8efe6f53ec


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="app/src/main/java/com/shangjin/frameecho/app/ui/player/components/VideoSurface.kt">

<violation number="1" location="app/src/main/java/com/shangjin/frameecho/app/ui/player/components/VideoSurface.kt:144">
P3: `whiteColor60` doesn't depend on `colorScheme`, so it's recomputed on every recomposition even though its value never changes. Hoist it to a top-level `private val whiteColor60 = Color.White.copy(alpha = 0.6f)` so the `.copy()` runs once instead of on every recomposition, consistent with this PR's allocation-avoidance goal.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

val scrimColor18 = colorScheme.scrim.copy(alpha = 0.18f)
val inverseSurfaceColor70 = colorScheme.inverseSurface.copy(alpha = 0.7f)
val inverseSurfaceColor60 = colorScheme.inverseSurface.copy(alpha = 0.6f)
val whiteColor60 = Color.White.copy(alpha = 0.6f)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: whiteColor60 doesn't depend on colorScheme, so it's recomputed on every recomposition even though its value never changes. Hoist it to a top-level private val whiteColor60 = Color.White.copy(alpha = 0.6f) so the .copy() runs once instead of on every recomposition, consistent with this PR's allocation-avoidance goal.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/main/java/com/shangjin/frameecho/app/ui/player/components/VideoSurface.kt, line 144:

<comment>`whiteColor60` doesn't depend on `colorScheme`, so it's recomputed on every recomposition even though its value never changes. Hoist it to a top-level `private val whiteColor60 = Color.White.copy(alpha = 0.6f)` so the `.copy()` runs once instead of on every recomposition, consistent with this PR's allocation-avoidance goal.</comment>

<file context>
@@ -132,13 +132,16 @@ fun VideoSurface(
+    val scrimColor18 = colorScheme.scrim.copy(alpha = 0.18f)
+    val inverseSurfaceColor70 = colorScheme.inverseSurface.copy(alpha = 0.7f)
+    val inverseSurfaceColor60 = colorScheme.inverseSurface.copy(alpha = 0.6f)
+    val whiteColor60 = Color.White.copy(alpha = 0.6f)
 
     LaunchedEffect(tapFeedbackIsPlaying) {
</file context>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant