Unity3D脚本协程执行顺序异常问题排查与修复求助
问题
我编写了两个Unity脚本:WebSourceConfig用于读取JSON配置文件,WebSourceLink用于在应用中渲染按钮。要求WebSourceLink必须在WebSourceConfig完成配置读取后再执行,否则应用会无数据可解析。我尝试用协程控制执行顺序,但发现无论配置文件是否完成下载,configSource.webConfig始终不为null,导致协程没等配置读取完成就直接执行了ReadData。
WebSourceLink脚本代码
public class WebSourceLink : MonoBehaviour { public WebSourceConfig configSource; //Buttons references public Button buttonPrefab; public GameObject Buttons; //Browser windows references public GameObject browserWindow; public GameObject Windows; private Vector2 _nextWindowPosition = new(-900f, 0f); void Start() { // Start coroutne to wait for read config file StartCoroutine(WaitForConfigRead()); } IEnumerator WaitForConfigRead() { // Continually check if the config file has been read while (configSource.webConfig == null) { // Use the yield return statement to pause the coroutine // until the next frame Debug.Log("Null data parsed"); yield return null; } Debug.Log(configSource.webConfig); // Once the file is read by WebSourceConfig, read the config data ReadData(); InvokeRepeating("ReadData", 300, 5 * 60); } // 省略其他方法... }
WebSourceConfig脚本代码
public class WebSourceConfig : MonoBehaviour { public WebConfiguration webConfig; // Store the last time the config file was read private DateTime lastReadTime = DateTime.MinValue; void Start() { // Start the coroutine to wait for the file to be downloaded StartCoroutine(WaitForConfigFile()); } IEnumerator WaitForConfigFile() { // Continually check if the config file has been downloaded yet while (!File.Exists(Path.Combine(Application.streamingAssetsPath, "config.json"))) { // Use the yield return statement to pause the coroutine // until the next frame yield return null; } // Once the file is downloaded, read the config file ReadConfigFile(); // Call the CheckConfigFile method every 5 minutes InvokeRepeating("CheckConfigFile", 300, 5 * 60); } void CheckConfigFile() { // Check for changes to the config file // If the file has changed, read it again if (HasConfigFileChanged()) { ReadConfigFile(); } } void ReadConfigFile() { try { // Use the Path.Combine method to create the full path to the JSON file string jsonPath = Path.Combine(Application.streamingAssetsPath, "config.json"); // Read the JSON file into a string string json = File.ReadAllText(jsonPath); // Convert the JSON string into a strongly-typed object webConfig = JsonUtility.FromJson<WebConfiguration>(json); } catch (System.Exception ex) { // Print the error message to the console Debug.LogError(ex.Message); } } bool HasConfigFileChanged() { // Get the last modified time of the file string jsonPath = Path.Combine(Application.streamingAssetsPath, "config.json"); var lastModifiedTime = File.GetLastWriteTime(jsonPath); // Check if the last modified time is different from the time when we last read the file if (lastModifiedTime != lastReadTime) { // Update the lastReadTime to the current time lastReadTime = lastModifiedTime; // Return true to indicate that the file has changed return true; } // Return false if the file has not changed return false; } }
问题分析
- Inspector手动赋值:如果在Unity编辑器中,
WebSourceConfig的webConfig字段被手动赋值(比如拖入了WebConfiguration实例),那么webConfig初始状态就不为null,协程的等待条件直接失效。 - JsonUtility解析特性:
JsonUtility.FromJson即使解析失败(JSON格式错误、字段不匹配),也不会返回null,而是返回一个所有字段为默认值的空WebConfiguration实例,这会让webConfig != null的判断成立,导致协程提前结束。 - 文件存在不代表有效:
WebSourceConfig的协程只检查文件是否存在,但文件存在不代表内容可解析,解析失败时webConfig依然会被赋值为空实例,同样触发WebSourceLink的协程结束条件。
修复方案
方案1:新增加载状态标记(推荐)
在WebSourceConfig中添加明确的加载状态标记,替代webConfig == null的判断逻辑,这是最可靠的方式。
修改WebSourceConfig
public class WebSourceConfig : MonoBehaviour { [HideInInspector] // 防止Inspector手动赋值 public WebConfiguration webConfig; // 新增:标记配置是否成功加载完成 public bool IsConfigLoaded { get; private set; } private DateTime lastReadTime = DateTime.MinValue; void Start() { StartCoroutine(WaitForConfigFile()); } IEnumerator WaitForConfigFile() { string jsonPath = Path.Combine(Application.streamingAssetsPath, "config.json"); while (!File.Exists(jsonPath)) { yield return null; } // 读取后更新加载状态 IsConfigLoaded = ReadConfigFile(); InvokeRepeating("CheckConfigFile", 300, 5 * 60); } void CheckConfigFile() { if (HasConfigFileChanged()) { // 更新加载状态 IsConfigLoaded = ReadConfigFile(); } } // 修改为返回bool,标识读取是否成功 bool ReadConfigFile() { try { string jsonPath = Path.Combine(Application.streamingAssetsPath, "config.json"); string json = File.ReadAllText(jsonPath); var tempConfig = JsonUtility.FromJson<WebConfiguration>(json); // 验证配置有效性(根据你的WebConfiguration结构调整,比如检查关键字段) if (tempConfig != null && !string.IsNullOrEmpty(tempConfig.someKeyField)) { webConfig = tempConfig; return true; } else { Debug.LogError("配置文件内容无效,关键字段缺失"); webConfig = null; return false; } } catch (System.Exception ex) { Debug.LogError($"读取配置失败:{ex.Message}"); webConfig = null; return false; } } // 保留原有HasConfigFileChanged方法 bool HasConfigFileChanged() { string jsonPath = Path.Combine(Application.streamingAssetsPath, "config.json"); var lastModifiedTime = File.GetLastWriteTime(jsonPath); if (lastModifiedTime != lastReadTime) { lastReadTime = lastModifiedTime; return true; } return false; } }
修改WebSourceLink的协程
IEnumerator WaitForConfigRead() { // 等待configSource存在且配置加载完成 while (configSource == null || !configSource.IsConfigLoaded) { Debug.Log("等待配置加载..."); yield return null; } Debug.Log("配置加载完成,开始渲染按钮"); ReadData(); InvokeRepeating("ReadData", 300, 5 * 60); }
方案2:修复webConfig的null判断逻辑
如果不想新增标记,可以修改ReadConfigFile方法,在解析失败或内容无效时将webConfig设为null,同时确保Inspector中webConfig字段留空。
void ReadConfigFile() { try { string jsonPath = Path.Combine(Application.streamingAssetsPath, "config.json"); string json = File.ReadAllText(jsonPath); var tempConfig = JsonUtility.FromJson<WebConfiguration>(json); // 验证配置有效性,无效则设为null if (tempConfig != null && !string.IsNullOrEmpty(tempConfig.someKeyField)) { webConfig = tempConfig; } else { webConfig = null; Debug.LogError("配置内容无效"); } } catch (System.Exception ex) { Debug.LogError($"读取配置失败:{ex.Message}"); webConfig = null; // 异常时强制设为null } }
同时给webConfig字段添加[HideInInspector],防止手动赋值:
[HideInInspector] public WebConfiguration webConfig;
内容的提问来源于stack exchange,提问作者Chenchen
相关产品推荐
相关产品推荐

