我正在使用UnityWebRequest从API获取搜索结果的JSON数组。与其屈服直到返回整个数组,我可以让我的代码一一处理结果吗?
任何方向都值得赞赏。
下面是一些代码:
public IEnumerator GetMovies(string q)
{
string uri = "http://www.omdbapi.com/?apikey=__&s=" + q;
using (UnityWebRequest r = UnityWebRequest.Get(uri))
{
yield return r.SendWebRequest();
if(r.isHttpError || r.isNetworkError)
{
Debug.Log(r.error);
}
else
{
SearchInfo info = JsonUtility.FromJson<SearchInfo>(r.downloadHandler.text);
if(info != null)
{
gameObject.GetComponent<EventManager>().onSearchInfoGet(info);
}
}
}
}
把它放在一个线程上
JsonUtility.FromJson
可以从后台线程调用此方法的字符串版本。
所以你可以尝试简单地做一些类似的事情
// A thread save queue
ConcurrentQueue<SearchInfo> callbacks = new ConcurrentQueue<SearchInfo>();
public IEnumerator GetMovies(string q)
{
var uri = "http://www.omdbapi.com/?apikey=__&s=" + q;
using (var r = UnityWebRequest.Get(uri))
{
yield return r.SendWebRequest();
if (r.isHttpError || r.isNetworkError)
{
Debug.Log(r.error);
}
else
{
// start the deserialization task in a background thread
// and pass in the returned string
Thread thread = new Thread(new ParameterizedThreadStart(DeserializeAsync));
thread.Start(r.downloadHandler.text);
// wait until the thread writes a result to the queue
yield return new WaitUntil(()=> !callbacks.IsEmpty);
// read the first entry in the queue and remove it at the same time
if (callbacks.TryDequeue(out var result))
{
GetComponent<EventManager>().onSearchInfoGet(result);
}
}
}
}
// This happens in a background thread!
private void DeserializeAsync(object json)
{
// now it shouldn't matter how long this takes
var info = JsonUtility.FromJson<SearchInfo>((string)json);
// dispatch the result back to the main thread
callbacks.Enqueue(info);
}
也许有更有效的方法可以将单个数据事件调度回主线程,然后是队列......但至少我可以说ConcurrentQueue
是线程保存;)
替代(也许(
而不是使用JsonUtility
您可以使用例如SimpleJSON
,您只需要在Assets
某处创建一个包含SimpleJSON.cs
内容的 C# 脚本。
假设像这样的 JSON
{
"Search" : [
{
"Title":"AB",
"Year":"1999",
"imdbID":"abcdefg",
"Type":"AB"
},
{
"Title":"IJ",
"Year":"2000",
"imdbID":"abcdefg",
"Type":"IJ"
},
{
"Title":"XY",
"Year":"2001",
"imdbID":"abcdefg",
"Type":"XY"
}
]
}
和你的SearchInfo
喜欢
// This you might not need anymore
[System.Serializable]
public class SearchInfo
{
public MovieSearchInfo[] Search;
}
[System.Serializable]
public class MovieSearchInfo
{
public string Title;
public string Year;
public string imdbID;
public string Type;
}
然后你可以使用它来解析"手动"的类,例如
// Give your IEnumerator a callback parameter
public IEnumerator GetMovies(string q, Action<JSONArray> OnSuccess = null)
{
var uri = "http://www.omdbapi.com/?apikey=__&s=" + q;
using (var r = UnityWebRequest.Get(uri))
{
yield return r.SendWebRequest();
if (r.isHttpError || r.isNetworkError)
{
Debug.Log(r.error);
}
else
{
// Not sure though if this call is faster then
// simply using JsonUtility ...
var N = JSON.Parse(r.downloadHandler.text);
var theJsonArray = N["Search"].Values;
// Now depending on what you actually mean by one-by-one
// you could e.g. handle only one MoveInfo per frame like
foreach (var item in theJsonArray)
{
var movieInfo = new MovieSearchInfo();
movieInfo.Title = item["title"];
movieInfo.Year = item["Year"];
movieInfo.imdbID = item["imdbID"];
movieInfo.Type = item["Type"];
// NOW DO SOMETHING WITH IT
// wait for the next frame to continue
yield return null;
}
}
}
}
否则,您也可以签出其他 JSON 库。