离线状态下显示Room数据库存储数据异常求助
问题:离线状态下Room数据库数据丢失,无法正常展示
我从自建API获取数据并存入Room数据库,但离线时数据库中的数据总是丢失,无法正常展示。我的需求如下:
- 若离线但数据库中有数据,在RecyclerView中展示数据,同时播放按钮提示无网络;
- 若离线且数据库中无数据,RecyclerView显示无数据。
网络状态检查代码
if (!isConnected){ program.text = "Requires internet" //startTime.visibility = View.INVISIBLE //endTime.visibility = View.INVISIBLE // emptyString.visibility = View.VISIBLE // emptyString.text = "No internet" apiViewModel.programs.observe(this) { programs -> run { adapter.submitList(programs) // Log.d("Programs", "$programs") } } play.setOnClickListener { Toast.makeText(this, "Requires internet", Toast.LENGTH_SHORT).show() } stop.setOnClickListener { finish() stopService(Intent(this, BackgroundStreamService::class.java)) } } else{ //startTime.visibility = View.VISIBLE //endTime.visibility = View.VISIBLE play.setOnClickListener { if(isPlaying){ play.setImageResource(R.drawable.baseline_play_arrow_24) stopService(Intent(this, BackgroundStreamService::class.java)) isPlaying = false }else{ startForegroundService(Intent(this, BackgroundStreamService::class.java)) isPlaying = true //play.setBackgroundResource(R.drawable.baseline_stop_24) play.setImageResource(R.drawable.baseline_stop_24) } } stop.setOnClickListener { finish() stopService(Intent(this, BackgroundStreamService::class.java)) } //fetchPrograms() apiViewModel.programs.observe(this) { programs -> run { adapter.submitList(programs) Log.d("Programs", "$programs") } } }
Repo代码
val programs: LiveData<List<Program>> = Transformations.map(programDao.getPrograms()){ it.asDomainModel() } suspend fun refreshPrograms(){ withContext(Dispatchers.IO){ val programs = NodejsApi.programApi.getProgramAsync().await() programDao.insertAll(programs) } }
问题排查及解决建议
统一LiveData观察逻辑
目前代码在网络状态分支中分别设置programs的观察者,容易导致重复观察或观察时机错误。建议将观察者移到网络判断外部,只初始化一次:// 移到onCreate或合适的初始化位置,只调用一次 apiViewModel.programs.observe(this) { programs -> adapter.submitList(programs) // 处理空数据状态 if (programs.isEmpty()) { emptyString.visibility = View.VISIBLE emptyString.text = if (!isConnected) "无数据" else "" } else { emptyString.visibility = View.GONE } } // 后续只处理网络状态对应的UI逻辑 if (!isConnected) { program.text = "需要网络" play.setOnClickListener { Toast.makeText(this, "需要网络", Toast.LENGTH_SHORT).show() } // ...其他离线逻辑 } else { // ...在线逻辑 }检查数据插入与查询逻辑
- 确认
programDao.insertAll的注解是否正确,若使用@Insert(onConflict = OnConflictStrategy.REPLACE),需确保在线刷新时不会误删已有数据;若要保留旧数据,可改用OnConflictStrategy.IGNORE。 - 检查
programDao.getPrograms()是否返回数据库中所有数据,避免查询条件错误导致数据无法被获取。 - 验证
asDomainModel()转换方法,确保实体类到领域模型的字段映射完全正确,没有遗漏或错误转换。
- 确认
确认数据是否真正存入数据库
在refreshPrograms()中添加日志,确认API返回的数据不为空,且插入数据库操作成功:suspend fun refreshPrograms(){ withContext(Dispatchers.IO){ val programs = NodejsApi.programApi.getProgramAsync().await() Log.d("Repo", "API返回数据:${programs.size}条") programDao.insertAll(programs) // 插入后查询一次,确认数据存在 val dbData = programDao.getPrograms().value Log.d("Repo", "数据库当前数据:${dbData?.size ?: 0}条") } }检查Room数据库配置
- 确保数据库实例是单例模式,避免多个实例导致数据不一致。
- 若进行过数据库版本升级,检查迁移逻辑是否正确,错误的迁移可能导致数据丢失。
完善离线状态的UI处理
按照需求,离线时:- 数据库有数据:展示RecyclerView,播放按钮点击提示无网络;
- 数据库无数据:显示无数据提示。
这部分逻辑可以放在programs的观察者中结合网络状态判断实现,如第一步的示例代码。
内容的提问来源于stack exchange,提问作者Job Kilonzo
相关产品推荐
相关产品推荐

