【问题标题】:C# / MonoTouch: how to call an async method when a ViewController is created/appearsC#/MonoTouch:创建/出现 ViewController 时如何调用异步方法
【发布时间】:2013-08-16 00:32:38
【问题描述】:

Xamarin released 支持 async/await,这确实简化了移动平台中响应式 UI 的开发。从现在开始,我想利用它并通过使用 async/await 来提高我的代码的编程水平。

但是,由于我对 C# 比较陌生,并且在我无法在我的代码中找到可以调用 async 方法的“挂钩”之前没有使用过 async/await。我知道事件处理程序是典型的地方(发生 IoC 的地方),但想象一下以下场景:

我想在加载 ViewController 时启动后台任务(而不是在按下按钮时)。

async Task PerformMyTaskAsync ()
{
    // ...
    await ... // another async API
    // ...
}

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();

    // .. initialize UI
    await PerformMyTaskAsync ();
}

显然我不能在ViewDidLoad 中等待PerformMyTaskAsync,因为ViewDidLoad 既不是异步方法也不是事件处理程序。

当视图控制器加载(或出现,无论如何)时启动后台任务的“替代”方法是什么?

【问题讨论】:

标签: c# xamarin.ios xamarin async-await


【解决方案1】:

最新的 Xamarin 稳定通道版本支持 ViewController 生命周期方法的 Async/Await 重载。试试:

public async override void ViewDidLoad()

【讨论】:

  • 如果异步方法不应该返回 void 的警告呢?
  • @Chucky 通常你从不想要从异步方法返回 void 以避免许多问题,因此警告。唯一的例外是事件处理程序,在这种情况下是生命周期方法(因此在这种情况下,您可以忽略警告)。确保将异步 void 中的任何代码包装在 try-catch 中。
  • 有关如何串行使用多个异步 Xamarin ViewController 生命周期方法的通用模式(以避免一些带有异步 void 的陷阱),请查看 my related question/answer
【解决方案2】:

不确定这是否是“最佳”方法,但您是否尝试过从 ViewDidLoad() 中触发一个事件,然后在该事件的处理程序中启动您的异步代码?

【讨论】:

  • 看起来不错的解决方法,我还没有看到任何其他代码这样做,但也许这会成为一种模式。
【解决方案3】:

因此,从一个事件中,从 UI 线程异步运行一些东西,如下所示:

Blah.OnEvent += onEvent;

protected async void onEvent(object sender, EventArgs ev)
{
...
}

void 不是错字 - 不幸的是,它是 Xamarin 针对异步 UI 事件遵循的反模式。

在某些有效场景中,您可能希望运行使 UI 等待的异步方法。例如,通过单击按钮调用 Navigation.PushAsync()。但是,您特别要求执行后台任务,这意味着它可能需要一段时间。为此,您不想让 UI 等待;您应该开始任务并立即返回。为此,您只需使用在任何 C# TPL 应用程序中使用的相同后台任务代码:

    public static void RunBg(Func<Task> fn)
    {
        Task.Run(fn).ConfigureAwait(false);
            // Uncomment to roll up exceptions
            //.GetAwaiter().GetResult();
    }

    public static void RunBgLong(Func<Task> fn)
    {
        Task.Factory.StartNew(fn, TaskCreationOptions.LongRunning).ConfigureAwait(false);
            // Uncomment to roll up exceptions
            //.GetAwaiter().GetResult();
    }

我同时提供这两者是因为 TPL 的创建者已经竭尽全力在幕后提供这两者。 2 的含义在其他问题中得到了更好的探索,尽管我相信“long”的区别是毫秒数。

所以,你会像这样开始你的任务:

public override void ViewDidLoad()
{
    base.ViewDidLoad();
    TaskHelper.RunBg(async () => {
        await someBgAsyncMethodGoesHere(arg1, arg2);
    );
}

【讨论】:

    猜你喜欢
    • 2013-07-12
    • 2013-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-06
    相关资源
    最近更新 更多