如何在线程内更新Xamarin.Forms中的静态字符串值?
首先咱们先搞定那个棘手的JSON解析报错:Error parsing positive infinity value. Path '', line 0, position 0.,这个问题大概率是流读取的线程时机错误导致的。你当前代码把reader.ReadToEnd()放在了Device.BeginInvokeOnMainThread的委托里,但响应流的读取必须在发起Web请求的后台线程完成——流对象并非线程安全,跨线程读取极易引发数据异常,进而出现这类奇怪的解析错误。
而静态username无法更新的问题,一方面和JSON解析失败直接相关(解析出错就不会执行username = userData.username),另一方面也可能是异步操作的时序问题导致的。
具体修复步骤:
1. 调整流读取的线程位置
把StreamReader.ReadToEnd()移到后台线程(BeginGetResponse回调内部、Device.BeginInvokeOnMainThread外部),先完整读取响应内容,再把字符串传到主线程解析JSON:
private void loadUserData() { username = "Test"; // 这行同步赋值会立刻生效,但异步请求的赋值需等待请求完成 Uri uri = new Uri("http://example.com/session-data.php?session_id=" + session); WebRequest request = WebRequest.Create(uri); request.BeginGetResponse((result) => { try { using (var response = request.EndGetResponse(result)) using (var stream = response.GetResponseStream()) using (var reader = new StreamReader(stream)) { // 先在后台线程读取完整响应文本 string page_result = reader.ReadToEnd(); // 切换到主线程处理JSON解析与变量更新 Device.BeginInvokeOnMainThread(() => { try { var jsonSerializer = new JsonSerializer(); // API返回单个JSON对象,无需循环读取 UserData userData = jsonSerializer.Deserialize<UserData>(new JsonTextReader(new StringReader(page_result))); if (userData != null) { username = userData.username; Debug.WriteLine($"用户名已更新为:{username}"); } } catch (Newtonsoft.Json.JsonReaderException readerExp) { string rEx = readerExp.Message; Debug.WriteLine($"JSON解析错误:{rEx}"); } }); } } catch (Exception exc) { string ex = exc.Message; Debug.WriteLine($"请求错误:{ex}"); } }, null); }
2. 修正JSON反序列化逻辑
你的API返回的是单个JSON对象,不需要设置SupportMultipleContent = true,也不需要while (jsonReader.Read())循环——这个循环会尝试读取多个JSON对象,反而会引发解析错误,直接反序列化到UserData对象即可。
3. 解决异步时序问题
如果调用loadUserData()后立刻访问username,此时异步请求还未完成,读取到的还是初始值或临时的"Test"。建议改用async/await模式替代旧的BeginGetResponse,确保请求完成后再继续后续操作:
private async Task loadUserDataAsync() { username = "Test"; Uri uri = new Uri("http://example.com/session-data.php?session_id=" + session); try { using (var client = new HttpClient()) { string page_result = await client.GetStringAsync(uri); UserData userData = JsonConvert.DeserializeObject<UserData>(page_result); if (userData != null) { username = userData.username; Debug.WriteLine($"用户名已更新为:{username}"); } } } catch (Exception exc) { Debug.WriteLine($"错误:{exc.Message}"); } }
调用时使用await loadUserDataAsync();,就能保证请求完成后再读取username。
4. 确保UserData类的可访问性
当前你的UserData类是默认的internal访问级别,Newtonsoft.Json反序列化内部类可能出现问题,改为public类更稳妥:
public class UserData { [JsonProperty("id")] public int id { get; set; } [JsonProperty("username")] public string username { get; set; } [JsonProperty("name")] public string name { get; set; } [JsonProperty("bio")] public string bio { get; set; } [JsonProperty("private")] public int isPrivate { get; set; } }
总结
- 流读取必须在后台线程完成,禁止跨线程到主线程读取
- 单个JSON对象无需循环反序列化,移除多余的循环和配置
- 使用
async/await保证异步操作的时序,避免读取未更新的变量 - 确保
UserData类为public,避免序列化失败
按照这些步骤修改后,应该就能解决JSON解析报错和用户名无法更新的问题了。
内容的提问来源于stack exchange,提问作者Kingbluesapphire

