c# - BeginInvokeOnMainThread 方法是否会循环并导致内存泄漏?

标签 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);
            }
        }
    }
}

最佳答案

继续

首先,让我们解决您关于 .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);
    }
}

更多线程建议

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

  • 如果任务的执行时间超过屏幕的刷新率,请在后台线程上执行。例如,如果屏幕的刷新率为 60Hz,则每秒更新 60 次,每 16.7 毫秒。因此,如果我们有一段需要 20 毫秒执行的代码块,我们需要在后台线程上执行它以确保我们不会卡住应用程序并丢掉任何帧。

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

关于c# - BeginInvokeOnMainThread 方法是否会循环并导致内存泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45530572/

相关文章:

c# - 使用 Unity IoC 时如何实现 Ninject .InSingletonScope()

xaml - 如何将一个元素并排放置?

c# - 将 android java 翻译成 xamarin c#

c# - xamarin.forms 中的应用内购买

uwp - Xamarin form-UWP - 在列表快速滚动时显示数据之前的黑色单元格

c# - 什么是 C# 等同于 C++ 句柄

c# - WPF 共享资源问题 - 没有 App.xaml,没有共享资源

c# - WPF MVVM 模式,ViewModel DataContext 问题

ios - UIWebView 使用 NSUrlProtocol Xamarin.Forms 缓慢加载

c# - 如何在 Xamarin 的本地通知中显示应用名称?