BeginInvokeOnMainThread方法是否可以循环并导致内存泄漏?

Ala*_*an2 8 c# xamarin xamarin.forms

我有工作,但是当我调试在我的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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Bra*_*ick 7

继续

首先,让我们解决您的问题.ContinueWith((arg) => { })).ContinueWith在原始文件Task完成后告诉更多代码执行.在我们的例子中,里面的代码ContinueWith将运行一次Device.BeginInvokeOnMainThread(() => ShowCards(cts.Token).

在这种情况下,里面没有代码ContinueWith,所以我们可以删除它.

冷冻

是的,我可以看到此代码有可能冻结UI.

BeginInvokeOnMainThread将队列化Action以在主线程(也称为UI线程)上运行.主线程一直在监听用户输入(点击屏幕上的按钮,捏合缩放等),如果此线程忙于执行长时间运行的任务,它将无法响应用户的输入直到完成; 因此你的应用程序将显示为冻结

代码await Task.Delay(500);由主线程调用.因此,我们告诉主线程冻结自己500毫秒,并无限循环.

一种解决方案是将这些代码包装Task.Run在后台线程中并释放主线程以监听/响应用户输入.

Task.Run(async () => 
{ 
    while (!ct.IsCancellationRequested)
    {
          await Task.Delay(500);
    }
}
Run Code Online (Sandbox Code Playgroud)

更多线程建议

  • BeginInvokeOnMainThread在需要更新UI时使用.99%的代码可以在后台线程上运行而没有任何问题.然而,1%是更新UI的代码; 任何更新UI的代码都必须在主线程上运行.

  • 如果执行的任务花费的时间超过了屏幕的刷新率,请在后台线程上执行.例如,如果屏幕的刷新率为60Hz,则每16.7ms更新60次/秒.因此,如果我们有一个需要20ms执行的代码块,我们需要在后台线程上执行它,以确保我们不冻结应用程序并删除任何帧.

    • 上面的代码看起来像是在访问数据库,我强烈建议你转移到这样的后台线程
await Task.Run(() => AS.cardCountForSelectedCategories = App.DB.GetCardCountForSelectedCategories());
Run Code Online (Sandbox Code Playgroud)