简体   繁体   English

从Firebase获取数据后尝试更改场景时Unity脚本停止工作

[英]Unity Script stop working when trying to change scene after get data from firebase

So when I tried to get data from Firebase RealTime Database, the data was received succefuly. 因此,当我尝试从Firebase RealTime数据库获取数据时,数据被成功接收。 But when I tried to change the scene, the script is just stop working. 但是,当我尝试更改场景时,脚本只是停止工作。 Here is my full script : 这是我的完整脚本:

using Firebase;
using Firebase.Database;
using Firebase.Extensions;
using Firebase.Unity.Editor;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class NewBehaviourScript : MonoBehaviour
{
    DependencyStatus dependencyStatus = DependencyStatus.UnavailableOther;
    protected bool isFirebaseInitialized = false;
    // Start is called before the first frame update
    private void Start()
    {

        FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task => {
            dependencyStatus = task.Result;
            if (dependencyStatus == DependencyStatus.Available)
            {
                InitializeFirebase();
            }
            else
            {
                Debug.LogError(
                  "Could not resolve all Firebase dependencies: " + dependencyStatus);
            }
        });
    }
    protected virtual void InitializeFirebase()
    {
        FirebaseApp app = FirebaseApp.DefaultInstance;
        // NOTE: You'll need to replace this url with your Firebase App's database
        // path in order for the database connection to work correctly in editor.
        app.SetEditorDatabaseUrl("https://frim-exam.firebaseio.com/");
        if (app.Options.DatabaseUrl != null)
            app.SetEditorDatabaseUrl(app.Options.DatabaseUrl);
        StartListener();
        isFirebaseInitialized = true;
    }

    void StartListener()
    {
        FirebaseDatabase.DefaultInstance
      .GetReference("Leaders")
      .GetValueAsync().ContinueWith(task => {
            if (task.IsFaulted)
            {
                // Handle the error...
            }
            else if (task.IsCompleted)
            {
                DataSnapshot snapshot = task.Result;
              // Do something with snapshot...
              Debug.Log("Done!");
              SceneManager.LoadSceneAsync("Scene2");
              Debug.Log("Done!!!");
          }
        });
    }
}

When I run this script, there are just show "Done!" 当我运行此脚本时,仅显示“完成!”。 log at the log console. 在日志控制台上登录。 The change scene script and below that, for example I want to write log "Done!!!" 更改场景脚本及其下的脚本,例如,我想写日志“ Done !!!”(完成!!!) after the scene changed, is not executed. 场景更改后,不执行。

why don't you use DontDestroyOnLoad for keeping the codes between different scene? 为什么不使用DontDestroyOnLoad来保持不同场景之间的代码? Because The load of a new Scene destroys all current Scene objects. 因为新场景的加载会破坏所有当前的场景对象。 For this case could you try the belowing code of yours. 对于这种情况,您可以尝试以下代码。

using Firebase;
using Firebase.Database;
using Firebase.Extensions;
using Firebase.Unity.Editor;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;


private static bool created = false;

// the belowing code is used for changing the scene without losing the script
    void Awake()
    {
        if (!created)
        {
            DontDestroyOnLoad(this.gameObject);
            created = true;
            Debug.Log("Awake: " + this.gameObject);
        }
    }

public class NewBehaviourScript : MonoBehaviour
{
DependencyStatus dependencyStatus = DependencyStatus.UnavailableOther;
protected bool isFirebaseInitialized = false;
// Start is called before the first frame update
private void Start()
{

    FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task => {
        dependencyStatus = task.Result;
        if (dependencyStatus == DependencyStatus.Available)
        {
            InitializeFirebase();
        }
        else
        {
            Debug.LogError(
              "Could not resolve all Firebase dependencies: " + dependencyStatus);
        }
    });
}
protected virtual void InitializeFirebase()
{
    FirebaseApp app = FirebaseApp.DefaultInstance;
    // NOTE: You'll need to replace this url with your Firebase App's database
    // path in order for the database connection to work correctly in editor.
    app.SetEditorDatabaseUrl("https://frim-exam.firebaseio.com/");
    if (app.Options.DatabaseUrl != null)
        app.SetEditorDatabaseUrl(app.Options.DatabaseUrl);
    StartListener();
    isFirebaseInitialized = true;
}

void StartListener()
{
    FirebaseDatabase.DefaultInstance
  .GetReference("Leaders")
  .GetValueAsync().ContinueWith(task => {
        if (task.IsFaulted)
        {
            // Handle the error...
        }
        else if (task.IsCompleted)
        {
            DataSnapshot snapshot = task.Result;
          // Do something with snapshot...
          Debug.Log("Done!");
          SceneManager.LoadSceneAsync("Scene2");
          Debug.Log("Done!!!");
      }
    });
}
}

So, the best answer is probably to just try to update to the latest version of the firebase SDK . 因此,最好的答案可能就是尝试将Firebase SDK更新到最新版本 The specific patch I'm thinking will help you is 6.5.0: 我想为您提供帮助的特定修补程序是6.5.0:

The instance of FirebaseApp, FirebaseAuth, FirebaseDatabase, FirebaseFunctions, FirebaseInstanceId and FirebaseStorage will be kept alive after creation until explicitly disposed. FirebaseApp,FirebaseAuth,FirebaseDatabase,FirebaseFunctions,FirebaseInstanceId和FirebaseStorage的实例在创建后将一直保持活动状态,直到明确处置为止。

So, as mentioned elsewhere, you probably just have to make sure scripts are marked as DontDestroyOnLoad(gameObject); 因此,就像在其他地方提到的那样,您可能只需要确保将脚本标记为DontDestroyOnLoad(gameObject); , basically telling the entire game object (assuming it's at the scene root) that it shouldn't go away when its parent scene changes. ,基本上是告诉整个游戏对象(假设它位于场景根),当其父场景发生变化时,它不应消失。 For details and caveats see the Unity documentation . 有关详细信息和注意事项,请参见Unity文档

There was also a change in the Firebase SDK that I think will help you out. 我认为Firebase SDK也有所更改,可以为您提供帮助。 When ever you call something like FirebaseApp.DefaultInstance , Firebase would do some amount of lazy initialization on that object. 每当您调用诸如FirebaseApp.DefaultInstance ,Firebase都会对该对象进行一些延迟的初始化。 As in, first check if DefaultInstance is null. DefaultInstance ,首先检查DefaultInstance是否为null。 If it is, create it and return it out. 如果是这样,请创建它并将其退回。 This is a typical singleton pattern. 这是典型的单例模式。

The change is that, for various reasons, this used to be a weak reference. 变化是,由于各种原因,这曾经是一个较弱的参考。 As of 6.5.0, this was made into a normal C# reference (which means it's much less likely to get cleaned up), which may get rid of many bugs around "the scene changed, and something stopped working." 从6.5.0版开始,它已成为普通的C#参考(这意味着它被清理的可能性要小得多),可以摆脱“场景改变,某些东西停止工作”周围的许多错误。

Barring that, just make sure you use DontDestroyOnLoad and make sure it's doing what you expect (ie: apply it to a game object at the root of the scene rather than a MonoBehaviour or a child object). 除非这样做, DontDestroyOnLoad确保使用DontDestroyOnLoad并确保它正在执行您期望的操作(即:将其应用于场景根部的游戏对象,而不是MonoBehaviour或子对象)。

--Patrick --Patrick

This is a classic Task continuation problem in Unity using Firebase. 这是使用Firebase的Unity中经典的任务延续问题。 When you use, ContinueWith it is not ensured to be called on the main Unity thread. 使用时,不能确保在Unity主线程上调用ContinueWith What you're trying to do SceneManager.LoadSceneAsync() requires to be executed on the Unity main thread. 您要执行的操作SceneManager.LoadSceneAsync()需要在Unity主线程上执行。 If you try to access GameObjects inside ContinueWith , even that will fail. 如果您尝试在ContinueWith内访问GameObjects,那将失败。 The code just ghosts out without any error in the console. 代码只是伪装出来,在控制台中没有任何错误。

The solution: Instead of ContinueWith , use ContinueWithOnMainThread from Firebase extensions which was made exactly for this reason. 解决方案:与其ContinueWith ,使用ContinueWithOnMainThread火力地堡扩展被做正是这个原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM