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

FireStore数据加载不稳定,文档ID匹配失效求助

问题排查请求

FireStore数据库数据拉取存在不稳定问题,新增基于首次拉取的二次数据获取逻辑后,问题反而加剧。用户歌单以文档ID形式存储,需通过ID匹配对应歌曲数据:

  • 已确认getAllUserPlaylists()可返回有效文档ID
  • 后续通过ID匹配歌曲数据的代码无法得到预期结果,仅在清除应用数据和缓存后约10%的概率能正常工作
  • 全程无可见报错,最终数据通过RecyclerView展示,该组件支持随数据变化自动更新UI

核心业务代码

// 获取用户数据
suspend fun getAllUserPlaylists():List<Playlists>
        = try{  FS_USER.get().await().toObjects(Playlists::class.java) }
          catch (e:Exception){ emptyList() /*getAllUserPlaylists()*/ }

// 调用上述方法
val allUserPlaylist =  GlobalScope.launch { vm.allUserPlaylists.postValue(MusicDB().getAllUserPlaylists()) }


runBlocking {
            // 等待数据拉取完成
            allUserPlaylist.join()
            Log.i("WORKS","${vm.allUserPlaylists.value}")

            // 匹配ID与歌曲数据
            vm.allUserPlaylists.value?.forEach {
                val q = arrayListOf<Song>()
                it.songsIDs.forEach { it2 ->
                    val t = FS_ALL_SONGS.document(it2).get().await().toObject(Song::class.java)
                    if (t != null) {
                        q.add(t)
                    }
                }
                // 更新歌单的歌曲列表
                val vmT = vm.allUserPlaylists.value!!
                vmT[vmT.indexOf(it)].songs = q
                vm.allUserPlaylists.postValue(vmT)
            }
  }

数据类定义

data class Song(val mediaID: String = "", val title: String = "",
                val artist: String = "", val songURL: String = "",
                val imgURL: String = "", val album: String = "")
data class Playlists(val name:String= "", val mainArtists: String = "",
                     var songs:ArrayList<Song> = arrayListOf(),
                     val songsIDs:ArrayList<String> = arrayListOf(),
                     val imgURL:String = "",var pinned:Boolean = false)

问题排查与修复建议

  1. 数据更新逻辑冲突

    • 直接修改Playlists对象的songs属性,再多次调用postValue,会因线程调度导致数据覆盖;同时indexOf依赖对象引用匹配,若缓存或复用对象会导致更新失败。
    • 修复:创建Playlists的副本更新songs,收集所有更新后的歌单后一次性postValue,避免频繁UI更新冲突。示例:
      val updatedPlaylists = vm.allUserPlaylists.value?.map { playlist ->
          val songs = playlist.songsIDs.mapNotNull { id ->
              runCatching { FS_ALL_SONGS.document(id).get().await().toObject(Song::class.java) }.getOrNull()
          }
          playlist.copy(songs = ArrayList(songs))
      } ?: emptyList()
      vm.allUserPlaylists.postValue(updatedPlaylists)
      
  2. 协程作用域不规范

    • 使用GlobalScope.launch无绑定生命周期,可能导致协程在页面销毁后仍运行,或数据回调时机混乱。
    • 修复:改用ViewModel的viewModelScope启动协程,确保协程与页面生命周期绑定。
  3. 异常处理缺失

    • 匹配歌曲数据时未捕获拉取异常,单个ID拉取失败会中断整个歌单的歌曲填充,且无报错日志。
    • 修复:在单个歌曲拉取逻辑外层添加runCatching捕获异常并打印日志,避免影响后续ID处理。
  4. 缓存干扰

    • FireStore默认会使用本地缓存,清缓存后才拉取新数据导致只有10%概率正常。
    • 修复:拉取时指定强制从服务器获取数据,示例:
      FS_USER.get(Source.SERVER).await().toObjects(Playlists::class.java)
      
  5. 递归重试风险

    • getAllUserPlaylists()的catch块注释了递归调用,若放开会导致无限递归拉取,引发栈溢出。
    • 修复:实现有限次数的重试逻辑,而非无限制递归。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 20:25:29