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

Android Kotlin游戏开发:Activity重绘更新失败求助

Android游戏Activity重绘问题解决方案(Kotlin)

为什么普通线程处理无效?

Android的UI更新必须在**主线程(UI线程)**执行,直接用子线程修改View属性或触发重绘会被系统拦截,而且Activity的生命周期回调(如onPause/onResume)会干扰子线程的绘制逻辑,导致重绘不生效或出现异常。


具体解决方案

1. 改用SurfaceView/TextureView(游戏开发首选)

SurfaceView拥有独立的绘制Surface和线程,完全避开UI线程的阻塞问题,是Android游戏开发的标准组件。

示例代码(Kotlin):

class GameSurfaceView(context: Context) : SurfaceView(context), Runnable {
    private var isRunning = false
    private var drawThread: Thread? = null
    private val surfaceHolder = holder

    override fun run() {
        while (isRunning) {
            // 锁定画布开始绘制
            val canvas = surfaceHolder.lockCanvas()
            canvas?.let {
                // 这里写你的游戏绘制逻辑(画背景、角色、动画等)
                it.drawColor(Color.BLACK)
                // 示例:画一个矩形
                it.drawRect(100f, 100f, 300f, 300f, Paint().apply { color = Color.RED })
                
                surfaceHolder.unlockCanvasAndPost(it) // 提交绘制内容
            }
            Thread.sleep(16) // 控制帧率(约60fps)
        }
    }

    // 启动绘制线程
    fun startDrawing() {
        isRunning = true
        drawThread = Thread(this)
        drawThread?.start()
    }

    // 停止绘制线程(避免后台消耗资源)
    fun stopDrawing() {
        isRunning = false
        drawThread?.join()
    }
}

在Activity中集成:

class GameActivity : AppCompatActivity() {
    private lateinit var gameView: GameSurfaceView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        gameView = GameSurfaceView(this)
        setContentView(gameView)
    }

    override fun onResume() {
        super.onResume()
        gameView.startDrawing()
    }

    override fun onPause() {
        super.onPause()
        gameView.stopDrawing()
    }
}

2. 用主线程安全方式触发重绘

如果必须基于普通View开发,确保所有重绘操作切换到主线程:

  • 使用runOnUiThread包裹重绘调用:
    // 子线程中计算游戏逻辑后,切换到主线程触发重绘
    Thread {
        // 游戏逻辑计算
        // ...
        runOnUiThread {
            gameView.invalidate() // 触发重绘
        }
    }.start()
    
  • 或者用Coroutines更简洁:
    lifecycleScope.launch(Dispatchers.IO) {
        while (isActive) {
            // 游戏逻辑计算
            // ...
            withContext(Dispatchers.Main) {
                gameView.invalidate()
            }
            delay(16)
        }
    }
    
  • 也可以直接用postInvalidate(),它会自动切换到主线程执行重绘:
    gameView.postInvalidate() // 子线程中直接调用也安全
    

3. 避免生命周期干扰

确保在Activity进入后台时停止绘制逻辑,恢复时重新启动:

  • 在onPause中暂停线程/协程,onResume中重启,防止后台无效绘制导致的内存泄漏或重绘异常。

内容的提问来源于stack exchange,提问作者Brian Packard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 20:06:28