异步事件处理程序有时会挂在 Xamarin.Forms
Posted
技术标签:
【中文标题】异步事件处理程序有时会挂在 Xamarin.Forms【英文标题】:async event handler sometimes hangs in Xamarin.Forms 【发布时间】:2018-12-18 17:42:54 【问题描述】:我有一个异步事件处理程序,只要文本更改,就会在我的输入字段中触发。这是一个 Xamarin.Forms 应用程序,我正在使用事件处理程序 TextChanged
来模拟我的条目中的“过度类型”功能,例如在插入键处于活动状态时编写文本。但是,这有时会导致应用程序在 await Task.Yield() 调用之后死锁。需要此调用才能获得正确的行为,否则在执行调用后插入符号不会进入正确的位置。我不知道为什么代码手以及如何解决这个问题,所以任何帮助/建议将不胜感激。我猜这个问题与我的异步编程知识不足有关。
private static async void OnOvertypeTextChanged(object sender, TextChangedEventArgs e)
var guid = Guid.NewGuid();
Debug.WriteLine($"DateTime.Now.ToString(): START guid.ToString()");
var entry = sender as CustomEntry;
if (entry.IsOvertypeRunning)
return;
else
entry.IsOvertypeRunning = true;
try
entry.TextChanged -= OnOvertypeTextChanged;
//Update value as in overtype mode
var oldVal = e.OldTextValue;
var newVal = e.NewTextValue;
int? carret = null;
//If new string is longer, we should go into overtype mode, otherwise ignore it
if (newVal?.Length > oldVal?.Length)
var i = entry.CursorPosition;
var overtyped = oldVal.Substring(0, i) + newVal[i] + ((oldVal.Length > (i + 1)) ? oldVal.Substring(i + 1) : "");
entry.Text = overtyped;
carret = i + 1;
//Check if new overtyped value is longer than max allowed size
if (entry.OvertypeLength != -1 && entry.Text.Length > entry.OvertypeLength)
var cut = entry.Text.Substring(0, entry.OvertypeLength);
//If new text would be longer, then cut it
entry.Text = cut;
if (carret >= cut.Length)
carret = cut.Length;
//For some reason, this is needed...
if (carret != null)
Debug.WriteLine($"DateTime.Now.ToString(): WAITING guid.ToString()");
await Task.Yield();
Debug.WriteLine($"DateTime.Now.ToString(): DONE_WAITING guid.ToString()");
Debug.WriteLine($"DateTime.Now.ToString(): SETTING_CURSOR guid.ToString() @ carret.Value.ToString()");
entry.CursorPosition = carret.Value;
Debug.WriteLine($"DateTime.Now.ToString(): CURSOR_SET guid.ToString()");
Debug.WriteLine($"DateTime.Now.ToString(): DONE guid.ToString()");
catch (Exception ex)
Debug.WriteLine($"DateTime.Now.ToString(): ERROR guid.ToString()", ex);
finally
entry.IsOvertypeRunning = false;
entry.TextChanged += OnOvertypeTextChanged;
Debug.WriteLine($"DateTime.Now.ToString(): END guid.ToString()");
所以会发生的是一切都会正常工作,只是在Entry上几个成功的焦点/取消焦点事件之后,它就会挂起。
所以日志记录会产生如下内容:
[0:] 18. 12. 2018 17:57:26: START bba4b754-8f22-4a14-ae28-8536d3a1e3d1
[0:] 18. 12. 2018 17:57:26: WAITING bba4b754-8f22-4a14-ae28-8536d3a1e3d1
[0:] 18. 12. 2018 17:57:26: DONE_WAITING bba4b754-8f22-4a14-ae28-8536d3a1e3d1
[0:] 18. 12. 2018 17:57:26: SETTING_CURSOR bba4b754-8f22-4a14-ae28-8536d3a1e3d1 @ 14
[0:] 18. 12. 2018 17:57:26: CURSOR_SET bba4b754-8f22-4a14-ae28-8536d3a1e3d1
[0:] 18. 12. 2018 17:57:26: DONE bba4b754-8f22-4a14-ae28-8536d3a1e3d1
[0:] 18. 12. 2018 17:57:26: END bba4b754-8f22-4a14-ae28-8536d3a1e3d1
[0:] 18. 12. 2018 17:57:26: START 71bf9809-6217-4d73-94df-817042a251b9
[0:] 18. 12. 2018 17:57:26: WAITING 71bf9809-6217-4d73-94df-817042a251b9
[0:] 18. 12. 2018 17:57:26: DONE_WAITING 71bf9809-6217-4d73-94df-817042a251b9
[0:] 18. 12. 2018 17:57:26: SETTING_CURSOR 71bf9809-6217-4d73-94df-817042a251b9 @ 14
[0:] 18. 12. 2018 17:57:26: CURSOR_SET 71bf9809-6217-4d73-94df-817042a251b9
[0:] 18. 12. 2018 17:57:26: DONE 71bf9809-6217-4d73-94df-817042a251b9
[0:] 18. 12. 2018 17:57:26: END 71bf9809-6217-4d73-94df-817042a251b9
[0:] 18. 12. 2018 17:57:31: START f9fca969-e141-4a07-968d-e32616323995
[0:] 18. 12. 2018 17:57:31: WAITING f9fca969-e141-4a07-968d-e32616323995
然后该应用程序变得无响应并显示消息“应用程序 X 没有响应...”
在调用 CLICK 中描述的 HttpClient 服务时,我也发生了同样的异步“死锁”
我猜问题可能类似?
【问题讨论】:
使用 Device.BeginInvokeOnMainThread(async()=>);把代码放在这个 事件处理程序中的整个代码还是? @AditKothari 是的,在事件处理程序中你可以写这个 @DenisVitez 为什么使用Task.Yield()
这似乎是个问题?你的方法中没有其他东西是异步的,所以为什么不同步运行它。 Task.Yield()
不是用来保持 UI 响应的。
@JSteward 我正在使用 Task.Yield() 来获得正确的行为(因此光标确实位于正确的位置)。但是我发现没有必要使用它,所以我调整了我的代码以摆脱它并且它不再锁定。但是我仍然不明白为什么首先会发生锁定:)
【参考方案1】:
就像@JSteward 善意地指出的那样,Task.Yield() 的使用不是必需的,因为它是应用程序挂起的原因,现在已经解决了。可以在此处找到 OnTextChanged 处理程序的更新代码,它模拟改写模式以及如何轻松地将其与 Entry 类的 C# 扩展一起使用: https://forums.xamarin.com/discussion/143533/is-it-possible-to-have-overtype-functionality-in-entry
我希望这对将来的某人有所帮助:)
【讨论】:
以上是关于异步事件处理程序有时会挂在 Xamarin.Forms的主要内容,如果未能解决你的问题,请参考以下文章