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

Android开发:While循环阻塞Intent启动,请求排查解决

Android循环启动Activity导致界面闪烁、无法跳转的问题解决

问题场景

  • 需求:循环启动LocationScan页面,必须获取到plate和location两类结果后才停止扫描
  • 异常表现:使用while循环实现时,屏幕持续闪烁、Toast不断弹出,LocationScan页面无法正常加载;禁用循环后,跳转功能恢复正常

原代码

循环启动Activity的代码

while (plate == "0" || location == "0") {
    Toast.makeText(this, "Starting scan", Toast.LENGTH_SHORT).show()
    val intent = Intent(this, LocationScan::class.java)
    startActivityForResult(intent, 0)
}

结果接收代码

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)

    if (requestCode == 0) {
        if (resultCode == RESULT_OK) {
            val result = intent.getStringExtra("result")

            if (result!![0] in 'a'..'z' || result!![0] in 'A'..'Z'){
                location = result
                println("$result is an location.")
            } else {
                plate = result
                println("$result is a plate.")
            }
        }
    }
}

问题原因

Android主线程负责UI渲染和用户交互,while循环会持续阻塞主线程:

  1. startActivityForResult是异步操作,不会立即返回结果,循环会无限制重复执行,不断创建Intent和弹出Toast
  2. 主线程被阻塞后,系统无法处理Activity跳转的UI初始化操作,导致页面无法加载,同时频繁的Toast触发造成屏幕闪烁

解决方案

放弃阻塞式的while循环,改用回调触发二次扫描的方式:在每次接收扫描结果后,判断是否还需要继续扫描,若未集齐两类结果则再次启动LocationScan。

修改后的代码(基于startActivityForResult)

// 初始化全局变量
private var plate = "0"
private var location = "0"

// 启动扫描的方法
private fun startScan() {
    Toast.makeText(this, "Starting scan", Toast.LENGTH_SHORT).show()
    val intent = Intent(this, LocationScan::class.java)
    startActivityForResult(intent, 0)
}

// 结果处理回调
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    
    if (requestCode == 0 && resultCode == RESULT_OK) {
        data?.let { intent ->
            val result = intent.getStringExtra("result") ?: return@let
            
            // 区分结果类型并赋值
            if (result[0].isLetter()) {
                location = result
                println("$result is a location.")
            } else {
                plate = result
                println("$result is a plate.")
            }
            
            // 判断是否需要继续扫描
            if (plate == "0" || location == "0") {
                startScan()
            } else {
                // 两类结果已集齐,结束流程
                Toast.makeText(this, "扫描完成", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

推荐方案:使用registerForActivityResult替代废弃API

由于startActivityForResult在API 30+已被标记为废弃,推荐使用registerForActivityResult实现:

private var plate = "0"
private var location = "0"

// 注册Activity结果回调
private val scanLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
    if (result.resultCode == RESULT_OK) {
        result.data?.let { intent ->
            val scanResult = intent.getStringExtra("result") ?: return@let
            
            if (scanResult[0].isLetter()) {
                location = scanResult
                println("$scanResult is a location.")
            } else {
                plate = scanResult
                println("$scanResult is a plate.")
            }
            
            if (plate == "0" || location == "0") {
                startScan()
            } else {
                Toast.makeText(this, "扫描完成", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

private fun startScan() {
    Toast.makeText(this, "Starting scan", Toast.LENGTH_SHORT).show()
    val intent = Intent(this, LocationScan::class.java)
    scanLauncher.launch(intent)
}

注意事项

  • 绝对禁止在Android主线程中执行无限循环或长时间阻塞操作,否则会引发ANR(应用无响应)错误
  • 所有UI相关操作必须在主线程执行,但主线程不能被阻塞,异步操作需通过回调、协程等方式处理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 03:00:01