Unity中C#协程异步加载SQL数据需两次点击的解决问询
解决Unity中SQL存档加载需点击两次按钮的问题
这是典型的异步操作时序问题——你的Load方法启动了一个协程去执行HTTP请求,但协程是异步运行的,你在调用Load后立刻检查LoadedData,这时候请求还没完成,数据自然还没赋值,所以第一次点击没效果;第二次点击时,之前的协程已经跑完,数据才存在。
下面给你几种直接有效的解决方案,按推荐程度排序:
方案1:使用回调函数(最直接)
修改SavingLoading脚本,让加载完成后触发回调,把数据处理逻辑放在回调里,确保只有数据加载完成才执行赋值:
// 修改SavingLoading中的Load和LoadCall方法 public void Load(string name, Action<string> onLoaded) { StartCoroutine(LoadCall(name, onLoaded)); } IEnumerator LoadCall(string name, Action<string> onLoaded) { WWWForm form = new WWWForm(); form.AddField("name", name); WWW www = new WWW(LoadPhP, form); yield return www; // 新增:处理网络请求错误 if (!string.IsNullOrEmpty(www.error)) { Debug.LogError($"加载数据失败:{www.error}"); onLoaded?.Invoke(""); yield break; } string _return = www.text; LoadedData = _return; // 数据加载完成后触发回调 onLoaded?.Invoke(_return); }
然后修改你的loadData方法,把赋值逻辑移到回调中:
public void loadData() { var savingLoading = GetComponent<SavingLoading>(); string username = GameObject.Find("LoginSystem").GetComponent<LoginSystem>().Username; savingLoading.Load(username, (loadedData) => { if (!string.IsNullOrEmpty(loadedData)) { string[] Data = loadedData.Split(','); Level = Convert.ToInt32(Data[0]); CurrentXp = Convert.ToInt32(Data[1]); currentHealth = Convert.ToInt32(Data[2]); maxHealth = Convert.ToInt32(Data[3]); Vector3 LoadedPos = new Vector3(Convert.ToSingle(Data[4]), Convert.ToSingle(Data[5]), Convert.ToSingle(Data[6])); transform.position = LoadedPos; } }); }
这样点击一次按钮,就能在请求完成后自动执行数据赋值了。
方案2:将loadData改为协程
如果习惯用协程的方式等待异步操作,可以把loadData改成协程,直接等待LoadCall完成:
// 修改loadData为协程 public IEnumerator loadData() { var savingLoading = GetComponent<SavingLoading>(); string username = GameObject.Find("LoginSystem").GetComponent<LoginSystem>().Username; // 等待LoadCall协程执行完毕 yield return savingLoading.LoadCall(username); if (!string.IsNullOrEmpty(savingLoading.LoadedData)) { string[] Data = savingLoading.LoadedData.Split(','); Level = Convert.ToInt32(Data[0]); CurrentXp = Convert.ToInt32(Data[1]); currentHealth = Convert.ToInt32(Data[2]); maxHealth = Convert.ToInt32(Data[3]); Vector3 LoadedPos = new Vector3(Convert.ToSingle(Data[4]), Convert.ToSingle(Data[5]), Convert.ToSingle(Data[6])); transform.position = LoadedPos; } }
注意:此时按钮的点击事件不能直接调用loadData,需要改成启动协程:
// 在按钮绑定的方法中写 StartCoroutine(loadData());
额外建议
- 尽量避免频繁调用
GetComponent和GameObject.Find,可以提前缓存这些引用,提升性能。 - 对分割后的数组做长度检查,避免因返回数据格式错误导致索引越界崩溃。
内容的提问来源于stack exchange,提问作者pvtctrlalt
相关产品推荐
相关产品推荐

