我有一个可以正常运行的应用程序,但是一段时间后我在我的iPhone上进行调试它挂起了手机,我唯一可以恢复的方法是对侧面按钮和主页按钮进行硬重置。
首先,可能是因为我的应用程序有内存泄漏?
这是应用程序的代码。特别是,我正在研究BeginInvokeOnMainThread
方法。有人能告诉我他们是否可以看到它的实施方式是否存在任何问题?另外,.ContinueWith((arg)
的目的是什么。
namespace Japanese
{
public partial class PhrasesFrame : Frame
{
CancellationTokenSource cts = new CancellationTokenSource();
public PhrasesFrame(PhrasesPage phrasesPage)
{
InitializeComponent();
this.phrasesPage = phrasesPage;
AS.phrasesFrame = this;
Device.BeginInvokeOnMainThread(() => ShowCards(cts.Token).ContinueWith((arg) => { }));
}
public void Disappearing()
{
cts.Cancel();
}
public async Task ShowCards(CancellationToken ct)
{
AS.cardCountForSelectedCategories = App.DB.GetCardCountForSelectedCategories();
while (!ct.IsCancellationRequested)
{
await Task.Delay(500);
}
}
}
}
答案 0 :(得分:7)
首先,让我们解答有关.ContinueWith((arg) => { }))
的问题。 ContinueWith
告知更多代码在原始Task
完成后执行。在我们的示例中,ContinueWith
内的代码将在Device.BeginInvokeOnMainThread(() => ShowCards(cts.Token)
完成后运行。
在这种情况下,ContinueWith
内没有代码,因此我们可以将其删除。
是的,我可以看到此代码有可能冻结UI。
BeginInvokeOnMainThread
会将Action
排队以在主线程(也称为UI线程)上运行。主线程一直在监听用户输入(点击屏幕上的按钮,捏合缩放等),如果此线程忙于执行长时间运行的任务,它将无法响应用户和#39;输入直到完成;因此你的应用程序将显示为冻结。
主线程正在调用代码await Task.Delay(500);
。因此,我们告诉主线程冻结自己500毫秒,并无限期地循环。
一种解决方案是将此代码包装在Task.Run
中,这将把它放在后台线程中,并释放主线程来监听/响应用户输入。
Task.Run(async () =>
{
while (!ct.IsCancellationRequested)
{
await Task.Delay(500);
}
}
仅在需要更新UI时使用BeginInvokeOnMainThread
。 99%的代码可以在后台线程上运行而没有任何问题。然而,1%是更新UI的代码;任何更新UI 的代码必须在主线程上运行。
如果执行的任务花费的时间超过了屏幕的刷新率,请在后台线程上执行。例如,如果屏幕的刷新率为60Hz,则每16.7ms更新60次/秒。因此,如果我们有一段需要20ms才能执行的代码块,我们需要在后台线程上执行它,以确保我们不会冻结应用程序并丢弃任何帧。
await Task.Run(() => AS.cardCountForSelectedCategories = App.DB.GetCardCountForSelectedCategories());