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

Android中使用Bitmap更新ImageView时应用崩溃,求解决方案

问题分析与解决方案

伙计,你的代码里有几个关键问题导致了崩溃,我帮你一一拆解:

1. 最致命的问题:跨线程操作UI组件

Android的UI组件(比如ImageView)只能在主线程中更新,你在后台Thread里直接调用imageView.setImageBitmap(bitmap),这绝对会触发崩溃——系统会抛出CalledFromWrongThreadException。这是Android开发的基础规则,千万不能违反!

2. 字节读取不完整的潜在问题

你调用Connection.inBytesCam?.read(byteArray)时,完全忽略了read()方法的返回值。DataInputStream.read(byte[])返回的是实际读取到的字节数,它不一定会一次性填满整个byteArray(比如网络传输时可能分批次到达)。如果读取的字节数小于76032,后续转Bitmap时就会因为数据不完整而出错。

3. Byte转Int的符号错误问题

Byte在Kotlin里是有符号类型(范围-128到127),直接调用byte.toInt()会把0x80-0xFF的字节转换成负数(比如0xFF的byte会变成-1),而Color.rgb()需要的是0-255的正数,这会导致颜色值错误,甚至可能让Bitmap创建失败。


修正后的完整代码

我把所有问题都修复了,还加入了循环更新的逻辑(满足你类似视频播放器的需求),同时加入了异常处理和线程生命周期管理:

class Cam : AppCompatActivity() {
    // 标记线程是否应该继续运行
    private var isRunning = true

    override fun onCreate(savedInstanceState: Bundle?) {
        Log.d("Cam activity", "onCreate")
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_cam)

        val buttonBack: Button = findViewById(R.id.button_back)
        val textView: TextView = findViewById(R.id.textView)
        val imageView: ImageView = findViewById(R.id.Image_update)

        // 启动图片接收线程
        Thread {
            Thread.sleep(1000)
            val expectedSize = 76032
            val byteArray = ByteArray(expectedSize)
            
            while (isRunning) {
                try {
                    // 确保读取到完整的字节数据
                    var totalRead = 0
                    while (totalRead < expectedSize) {
                        val read = Connection.inBytesCam?.read(byteArray, totalRead, expectedSize - totalRead) ?: 0
                        if (read <= 0) {
                            // 连接断开,退出循环
                            break
                        }
                        totalRead += read
                    }

                    if (totalRead != expectedSize) {
                        Log.e("Cam", "读取字节不完整,预期$expectedSize,实际$totalRead")
                        continue
                    }

                    // 转换字节数组为像素数组,修复符号问题
                    val nrOfPixels = byteArray.size / 3
                    val pixels = IntArray(nrOfPixels)
                    for (i in 0 until nrOfPixels) {
                        // 用0xFF & byte.toInt()获取无符号的0-255数值
                        val r = byteArray[3 * i].toInt() and 0xFF
                        val g = byteArray[3 * i + 1].toInt() and 0xFF
                        val b = byteArray[3 * i + 2].toInt() and 0xFF
                        pixels[i] = Color.rgb(r, g, b)
                    }

                    // 创建Bitmap
                    val bitmap = Bitmap.createBitmap(pixels, 176, 144, Bitmap.Config.ARGB_8888)
                    
                    // 切换到主线程更新ImageView
                    runOnUiThread {
                        imageView.setImageBitmap(bitmap)
                        textView.text = "已更新图片:${System.currentTimeMillis()}"
                    }

                    // 控制帧率,比如30帧/秒,可根据需求调整
                    Thread.sleep(33)
                } catch (e: Exception) {
                    Log.e("Cam", "图片更新出错", e)
                    // 出错后可以尝试重连,或者退出循环
                    break
                }
            }
        }.start()

        buttonBack.setOnClickListener {
            // 停止线程,避免内存泄漏
            isRunning = false
            // 直接在主线程启动新Activity,不需要额外开线程
            val intent = Intent(this@Cam, ControlActivity::class.java)
            startActivity(intent)
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        // Activity销毁时停止线程,释放资源
        isRunning = false
        // 如果Socket连接还开着,记得关闭
        Connection.inBytesCam?.close()
        Connection.socket?.close()
    }
}

额外的注意事项

  • 线程生命周期管理:我加入了isRunning标记,在Activity销毁时停止后台线程,避免内存泄漏和空指针异常。
  • Socket资源释放:记得在onDestroy里关闭Socket和输入流,否则会占用系统资源。
  • 异常处理:加入了try-catch捕获异常,方便你查看日志定位问题。
  • 帧率控制:用Thread.sleep(33)实现大概30帧/秒的更新速度,你可以根据实际需求调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 10:40:39