You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

启动while循环后App卡顿、界面无响应问题求助

问题分析与解决方案

核心问题

  1. 主线程被阻塞:直接在UI线程调用gameloop.loop()的死循环会完全占用主线程,导致Compose无法更新UI,界面切换、按钮状态同步全部失效。
  2. 无帧率控制:循环无间隔执行会导致CPU占用过高,同时玩家移动逻辑执行速度不受控,游戏逻辑异常。
  3. 线程安全问题:UI线程更新的按钮状态(jumpButton等),后台线程读取时可能无法获取最新值。

修复方案

1. 重构游戏循环至后台线程并添加帧率控制

修改Gameloop类,将循环移至后台线程,并固定帧率避免资源浪费:

package com.example.jumpking.ui.theme

class Gameloop(
    private val game: Game
) {
    var jumpPower = 1f
    var jumpY = 0f
    private val targetFps = 60
    private val frameTimeNs = 1_000_000_000 / targetFps

    fun startLoop() {
        Thread {
            while (Application.gamestatus == Application.GAMESTATUS.RUNNING) {
                val startTime = System.nanoTime()

                // 同步访问游戏状态,保证线程安全
                synchronized(game) {
                    if (game.jumpButton) {
                        game.player.move(0f, jumpPower)
                    }
                    if (game.leftButton && !game.rightButton) {
                        game.player.move(-jumpPower, 0f)
                    }
                    if (!game.leftButton && game.rightButton) {
                        game.player.move(jumpPower, 0f)
                    }
                }

                // 计算帧间隔,控制帧率
                val elapsedTime = System.nanoTime() - startTime
                val sleepTime = frameTimeNs - elapsedTime
                if (sleepTime > 0) {
                    Thread.sleep(sleepTime / 1_000_000, (sleepTime % 1_000_000).toInt())
                }
            }
        }.start()
    }
}

2. 在Compose生命周期内启动游戏循环

修改MainActivity,使用LaunchedEffect在游戏状态激活时启动循环,避免阻塞UI线程:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            JumpKingTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    val gameclass = Game()
                    val gameloop = Gameloop(gameclass)
                    when (Application.currentState) {
                        Application.GAMESTATE.SCOREBOARD -> ScoreboardScreen()
                        Application.GAMESTATE.PLAYING -> {
                            gameclass.GameScreen(gameloop)
                            // 仅在进入游戏状态时启动循环
                            LaunchedEffect(Unit) {
                                gameloop.startLoop()
                            }
                        }
                        Application.GAMESTATE.MENU -> MenuScreen()
                    }
                }
            }
        }
    }
}

额外优化建议

  • 将游戏中的按钮状态变量(jumpButton、leftButton等)标记为@Volatile,或使用线程安全的状态容器,进一步保障线程间状态同步。
  • 若使用Compose的状态管理(如MutableState),可直接利用其线程安全特性,替代synchronized块。

内容的提问来源于stack exchange,提问作者Teodor Nyman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 11:06:34