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)
问题排查与修复建议
数据更新逻辑冲突
- 直接修改
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)
- 直接修改
协程作用域不规范
- 使用
GlobalScope.launch无绑定生命周期,可能导致协程在页面销毁后仍运行,或数据回调时机混乱。 - 修复:改用ViewModel的
viewModelScope启动协程,确保协程与页面生命周期绑定。
- 使用
异常处理缺失
- 匹配歌曲数据时未捕获拉取异常,单个ID拉取失败会中断整个歌单的歌曲填充,且无报错日志。
- 修复:在单个歌曲拉取逻辑外层添加
runCatching捕获异常并打印日志,避免影响后续ID处理。
缓存干扰
- FireStore默认会使用本地缓存,清缓存后才拉取新数据导致只有10%概率正常。
- 修复:拉取时指定强制从服务器获取数据,示例:
FS_USER.get(Source.SERVER).await().toObjects(Playlists::class.java)
递归重试风险
getAllUserPlaylists()的catch块注释了递归调用,若放开会导致无限递归拉取,引发栈溢出。- 修复:实现有限次数的重试逻辑,而非无限制递归。
内容的提问来源于stack exchange,提问作者Aarav Shah
相关产品推荐
相关产品推荐

