Unity跨场景后Firebase Realtime Database ValueChanged失效问题
Unity Firebase Realtime Database 跨场景异常问题
问题背景
我在使用Unity开发游戏,计划将用户数据存储至Firebase Realtime Database(下文简称Firebase)。最初设计的实现方案为:创建一个GameObject,为其挂载MonoUser脚本,在启动场景完成数据加载;脚本中注册Firebase的ValueChanged事件监听,当Firebase侧数据发生变更时,自动同步更新GameObject内存储的用户数据。
原本计划让该GameObject在整个游戏生命周期内跨场景存活,无需重复处理用户数据加载逻辑,但实际实现时遇到两个异常问题:
- 将该GameObject从一个场景移动到另一个场景后,
ValueChanged监听方法失效,不再接收Firebase的数据变更推送;尝试设置全程加载的常驻场景挂载该GameObject,在加载新场景的瞬间,ValueChanged监听同样会停止工作。 - 其他使用Firebase的GameObject在调用
setDatabaseValues或ContinueWithOnMainThread方法前运行完全正常,但这两个方法的逻辑只会在停止Unity运行模式时才会执行,且执行后结果符合预期。
问题2复现代码
Debug.Log("Log 1"); DatabaseReference databaseReference = FirebaseDatabase.DefaultInstance.RootReference; Debug.Log("Log 2"); this.userName = userName; FirebaseDatabase.DefaultInstance .GetReference(userName) .GetValueAsync().ContinueWithOnMainThread(task => { if (task.IsFaulted) { Debug.Log("Log 3"); } else if (task.IsCompleted) { DataSnapshot snapshot = task.Result; Debug.Log("Log 4"); this.uuid = snapshot.Child("uuid").GetValue(true).ToString(); Debug.Log("Log 5"); } });
运行时Log 2会立即打印,但Log 4只会在结束游戏运行时才输出。
问题解答
1. 跨场景传递的GameObject能否保留正常工作的Firebase ValueChanged监听?
完全可以,监听失效和跨场景逻辑本身没有关系,基本都是生命周期处理失误导致的,常见原因如下:
- 标记
DontDestroyOnLoad的常驻GameObject没有做单例校验,场景切换时新场景生成了同名脚本实例,旧实例被销毁,持有的DatabaseReference和监听注册信息随之失效。 - 脚本生命周期方法逻辑有误:场景切换时常驻对象的
OnDisable方法会被触发,如果在OnDisable里写了ValueChanged -= 回调方法的逻辑,会直接解绑监听,切场景后自然收不到推送。 - 场景加载过程中误卸载了Firebase SDK自动生成的
FirebaseServices调度对象,SDK失去主线程驱动后,所有监听、异步回调都会停止工作。
2. 是否必须在每个场景单独创建Firebase相关对象、重复下载用户数据?
不需要,这种做法会造成不必要的流量开销和逻辑冗余,正确的实现方式是全局单例管理:
- 给挂载用户数据管理脚本的GameObject调用
DontDestroyOnLoad(gameObject),在Awake阶段做单例判断,发现重复实例直接销毁,保证整个游戏生命周期内只有一个数据管理实例存在。 - Firebase初始化逻辑(
CheckAndFixDependenciesAsync)只需要在游戏启动的第一个场景执行一次,初始化完成后再执行首次用户数据拉取、ValueChanged监听注册,后续所有场景直接从单例对象读取缓存的用户数据即可,不需要重复拉取。 - 禁止在每个场景的启动逻辑里重复初始化Firebase、重复注册监听,避免覆盖全局实例的引用。
3. setDatabaseValues、ContinueWithOnMainThread逻辑为什么仅在停止Unity运行时触发?
这类回调延迟到退出播放模式才执行的核心原因是主线程调度被阻塞,或者Firebase初始化未完成就调用了接口,常见触发场景:
- 调用异步接口后存在阻塞主线程的逻辑:比如写了
task.Wait()、死循环、单帧超大计算量逻辑,把Unity主线程卡死。ContinueWithOnMainThread的回调依赖Unity每帧的主线程调度,主线程被阻塞时回调会一直排队,直到退出播放模式阻塞被释放才会执行。 - 未等待Firebase初始化完成就调用数据库接口:必须等
CheckAndFixDependenciesAsync返回DependencyStatus.Available状态后,再调用数据库读写、监听注册接口,否则任务会一直卡在等待初始化的队列中,不会触发回调。 - SDK版本兼容问题:部分旧版本Firebase Unity SDK在Unity 2021及以上版本中存在主线程调度bug,升级到最新稳定版SDK即可解决。
额外提示:你贴的复现代码中this.userName = userName属于无效自赋值,注意检查是否因为参数和类字段重名,导致实际传入的数据库路径参数没有正确赋值。
内容的提问来源于stack exchange,提问作者xBarkeeper
相关产品推荐
相关产品推荐

