安卓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
相关产品推荐
相关产品推荐

