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

Android Kotlin项目中Realm读写无数据问题排查求助

Realm写入后无法读取数据的问题排查与修复

核心问题分析

  • Realm实例线程绑定:主线程初始化的realm实例不能跨线程调用executeTransaction,Realm对象是线程独占的,跨线程使用会直接导致数据写入失败。
  • 未处理输入异常:editTextInt.text.toString().toInt()如果输入非数字会抛出NumberFormatException,直接中断写入流程且无错误提示。
  • 事务执行不规范:子线程中未正确获取和关闭Realm实例,可能引发资源泄漏或数据写入异常。

修复后的代码实现

1. 数据类(保持原有结构)

open class DataItemExtra : RealmObject {
    @PrimaryKey
    var id: String? = null
    var strVal: String = ""
    var intVal: Int = 0
    var extra: String = "extra"

    constructor(id: String?, s: String, n: Int) {
        this.id = id
        this.strVal = s
        this.intVal = n
    }

    constructor() // Realm要求的空构造函数
}

2. Activity代码修复

class MainActivity : AppCompatActivity() {
    private lateinit var realmConfig: RealmConfiguration

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val buttonSet = findViewById<Button>(R.id.buttonSet)
        val buttonGet = findViewById<Button>(R.id.buttonGet)
        val editTextString = findViewById<EditText>(R.id.editText)
        val editTextInt = findViewById<EditText>(R.id.editNum)
        val textRes = findViewById<TextView>(R.id.textRes)

        Realm.init(this)
        val realmName = "My Project"
        realmConfig = RealmConfiguration.Builder()
            .schemaVersion(1)
            .deleteRealmIfMigrationNeeded()
            .name(realmName)
            .build()

        buttonSet.setOnClickListener {
            val strVal = editTextString.text.toString().trim()
            val intStr = editTextInt.text.toString().trim()
            
            // 输入校验
            if (strVal.isEmpty() || intStr.isEmpty()) {
                Toast.makeText(this, "请输入完整内容", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }
            val intVal = try {
                intStr.toInt()
            } catch (e: NumberFormatException) {
                Toast.makeText(this, "请输入有效数字", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }

            Toast.makeText(this, "$strVal : $intVal", Toast.LENGTH_LONG).show()

            // 子线程独立获取Realm实例执行写入
            Thread {
                Realm.getInstance(realmConfig).use { realm ->
                    realm.executeTransaction { transactionRealm ->
                        val di = DataItemExtra("keyVal", strVal, intVal)
                        transactionRealm.insertOrUpdate(di)
                    }
                }
                // 主线程提示写入结果
                runOnUiThread {
                    Toast.makeText(this, "数据写入成功", Toast.LENGTH_SHORT).show()
                }
            }.start()
        }

        buttonGet.setOnClickListener {
            // 主线程获取Realm实例读取数据
            Realm.getInstance(realmConfig).use { realm ->
                val tasks: RealmResults<DataItemExtra> = realm.where<DataItemExtra>().findAll()
                textRes.text = ""
                val rSize = tasks.size
                if (rSize != 1) {
                    textRes.text = "数据数量异常:$rSize"
                } else {
                    val d = tasks[0]
                    textRes.text = "${d.id}, ${d.strVal}, ${d.intVal}, ${d.extra}"
                }

                tasks.forEach { d ->
                    Log.d("REALM-RES", "${d.id}, ${d.strVal}, ${d.intVal}, ${d.extra}")
                }
            }
        }
    }
}

关键修改说明

  1. 线程安全的Realm实例管理:

    • 不再全局持有Realm实例,而是在需要的线程中通过Realm.getInstance(realmConfig)获取,并用use函数自动关闭,避免资源泄漏。
    • 写入操作在子线程独立获取实例,严格遵循Realm线程绑定规则。
  2. 输入校验与异常捕获:

    • 增加空值和数字格式校验,避免因输入错误导致写入流程中断。
  3. 数据读取规范:

    • 读取时在主线程正确获取Realm实例,确保能拿到实时更新的数据。

额外建议

  • 推荐使用Realm Kotlin扩展库(io.realm:realm-ktx),可以用realm.write { ... }简化事务操作,代码更简洁。
  • 读取大量数据时建议放在子线程执行,避免阻塞UI线程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 13:17:02