什么时候在ViewModels中使用ConfigureAwait(false)有问题?

时间:2018-12-10 14:47:30

标签: xamarin mvvm configureawait

我想知道在哪种情况下使用

会遇到问题
ConfigureAwait(false)

在我的(Xamarin)MVVM方法中。这主要是因为我没有完全理解视图和视图模型及其属性与底层模型彼此之间必须具有的同步上下文。

1 那可观察的集合呢?

// VM
public ObservableCollection<SomeThing> SomeThings { get; set; }
// ...
public Task InitWorkload()
{
    SomeThings = await DbService.GetSomeThings(); // <-- Should need synchronization context, doesn't it?
}

// Service
public Task<SomeThings> GetSomeThings()
{
    result = await CallToDb.ConfigureAwait(false); // <-- This is UI agnostic and shouldn't care about context or does it?
    return result;
}

2 导航(在这种情况下,需要FreshMvvm的帮助)又如何呢?

private async Task CloseWindow()
{
    await CoreMethods.PopPageModel(); // <-- Should need synchronization context, doesn't it?
}

1 个答案:

答案 0 :(得分:1)

要回答标题问题,“何时在ViewModels中使用ConfigureAwait(false)有问题?”是“从不”。在视图模型中的使用无关紧要。重要的是调用async方法后要在哪个线程上运行,无论您是否在视图模型中都无关紧要。使用ConfigureAwait(false)可能唯一有问题的时间是您是否想返回调用异步方法之前正在运行的线程。

SynchronizationContext class上的文档仅供参考。

也许解释ConfigureAwait(false)的工作是回答此问题的最佳方法。当像这样调用异步方法时:

var x = await SomeMethodAsync();
var y = x;

代码var y = x将在异步方法被调用之前的工作线程上运行,即异步方法调用之前的同步上下文,但是,如果您使用ConfigureAwait(false),例如:

var x = await SomeMethodAsync().ConfigureAwait(false);
var y = x;

然后,代码var y = x将在返回时与SomeMethodAsync方法运行的线程相同。 (大概SomeMethodAsync使用Task.RunThread.StartNew这是启动新线程的主要方法... await不会启动新线程,它只是语法糖允许您的异步代码更具可读性,从而使异步方法调用之后的代码不必是委托方法或lambda,而可以像同步代码一样内联。)

因此,您需要的内容取决于可能需要更新的内容。任何UI更新都需要在Main或UI线程上运行。您始终可以使用Device.BeginInvokeOnMainThread(Action)将代码封送至Main或UI线程。

通常,当您处于按钮单击处理程序事件中时,事件处理程序方法开始在UI线程上运行。如果您需要调用一个异步方法然后更新某些UI,则不要使用ConfigureAwait(false),这样在异步方法之后,您将返回到Main / UI线程并可以更新UI。如果不需要更新任何UI,请随时调用ConfigureAwait(false),以便在不需要在该线程上运行时不必不必要地返回该UI线程。

在某些情况下,如果要从在UI线程上启动的一个方法调用多个异步方法,则可能要使用ConfigureAwait(false),这样就不会从多个后台线程来回切换到UI线程。时间,这会导致性能问题,但是,所有非UI的工作都是在后台线程上完成的,然后您可以在必要时手动将其编组回UI线程。

对于ObservableCollection,它没有线程关联性,即当对象只能在其创建时所在的同一线程上进行更新或修改,但是它也不安全,因此最好计划是仅在创建该线程的同一线程上访问或更改ObservableCollection,最有可能是在Main / UI线程上。