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

安卓Kotlin开发遇Cursor空安全报错、onActivityResult弃用及cursor初始化问题

Android Kotlin开发三类问题解决方案

1. 空安全调用报错解决

报错信息为Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type Cursor?

  • 原因:contentResolver.query() 方法返回值为可空类型Cursor?,Kotlin强制要求可空类型调用方法时必须做空安全处理,避免空指针崩溃
  • 解决方式:优先用判空包裹逻辑,不推荐直接使用!!强转:
cursor?.let { safeCursor ->
    safeCursor.moveToFirst()
    val columnIndex = safeCursor.getColumnIndex(filePathColumn[0])
    // 其他cursor操作
    safeCursor.close() // 用完必须关闭cursor,避免内存泄漏
}

推荐使用Kotlin自带的use扩展函数,会自动完成cursor关闭操作,无需手动调用close:

cursor?.use { safeCursor ->
    safeCursor.moveToFirst()
    val columnIndex = safeCursor.getColumnIndex(filePathColumn[0])
}

2. onActivityResult弃用问题解决

  • 原因:AndroidX Activity 1.2.0、Fragment 1.3.0版本之后,官方正式废弃onActivityResult方法,推荐使用Activity Result API作为替代方案
  • 解决步骤:
    • 第一步在Activity/Fragment中注册结果启动器,替代原有请求码判断逻辑
// 注册图片选择启动器
private val pickImageLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
    uri ?: return@registerForActivityResult // 选择结果为空直接返回
    // 此处写入原onActivityResult中拿到选择结果后的业务逻辑
    val filePathColumn=arrayOf(MediaStore.Images.Media.DATA)
    contentResolver.query(uri, filePathColumn, null, null, null)?.use { safeCursor ->
        safeCursor.moveToFirst()
        val columnIndex = safeCursor.getColumnIndex(filePathColumn[0])
        // 后续业务逻辑
    }
}
  • 第二步替换原有触发图片选择的逻辑:
// 原来调用startActivityForResult的位置替换为启动器调用
pickImageLauncher.launch("image/*")
  • 第三步删除原有重写的onActivityResult方法即可

3. cursor未初始化报错解决

  • 原因:你代码中的cursor是在if(requestCode==PICK_IMAGE_CODE && data!=null)代码块内部声明的局部变量,块外无法访问;同时外层声明的cursor变量未提前赋值,存在未初始化就调用的风险
  • 解决方式:
    要么将所有cursor相关操作都放在if代码块内部,和cursor声明保持同一作用域;要么提前将cursor声明为可空类型并赋值为null,调用前先做空判断
  • 修正后的原有逻辑代码示例(暂不替换Activity Result API的场景):
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    // 增加resultCode == RESULT_OK判断,避免用户取消选择后仍执行逻辑
    if(requestCode == PICK_IMAGE_CODE && resultCode == RESULT_OK && data != null) {
        val selectedImage = data.data ?: return
        val filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
        // 所有cursor操作都放在if块内部执行
        contentResolver.query(selectedImage, filePathColumn, null, null, null)?.use { cursor ->
            cursor.moveToFirst()
            val columnIndex = cursor.getColumnIndex(filePathColumn[0])
            // 后续业务逻辑
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 22:48:04