- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我感兴趣的是为什么我们需要调用 InvokeOnMainThread 而这将是 TaskScheduler.FromCurrentSynchronizationContext() 的主要意图和职责?
我在 iPhone 应用程序的 Monotouch 中使用 TPL 来执行一些后台任务并通过记者类更新 UI。但似乎 TaskScheduler.FromCurrentSynchronizationContext() 没有像您期望的那样同步到 UI 线程。此时我设法通过使用 InvokeOnMainThread 使其工作(但仍然感觉不对),如 Threading 所述Xamarin 网站上的主题。
我还发现了一个报告(类似)bug在 BugZilla,这似乎已经解决了……还有另一个 threading question关于在 MonoTouch 中使用后台线程的首选方式。
下面是用于说明我的问题并展示行为的代码片段。
private CancellationTokenSource cancellationTokenSource;
private void StartBackgroundTask ()
{
this.cancellationTokenSource = new CancellationTokenSource ();
var cancellationToken = this.cancellationTokenSource.Token;
var progressReporter = new ProgressReporter ();
int n = 100;
var uiThreadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine ("Start in thread " + uiThreadId);
var task = Task.Factory.StartNew (() =>
{
for (int i = 0; i != n; ++i) {
Console.WriteLine ("Work in thread " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep (30);
progressReporter.ReportProgress (() =>
{
Console.WriteLine ("Reporting in thread {0} (should be {1})",
Thread.CurrentThread.ManagedThreadId,
uiThreadId);
this.progressBar.Progress = (float)(i + 1) / n;
this.progressLabel.Text = this.progressBar.Progress.ToString();
});
}
return 42; // Just a mock result
}, cancellationToken);
progressReporter.RegisterContinuation (task, () =>
{
Console.WriteLine ("Result in thread {0} (should be {1})",
Thread.CurrentThread.ManagedThreadId,
uiThreadId);
this.progressBar.Progress = (float)1;
this.progressLabel.Text = string.Empty;
Util.DisplayMessage ("Result","Background task result: " + task.Result);
});
}
记者类有这些方法
public void ReportProgress(Action action)
{
this.ReportProgressAsync(action).Wait();
}
public Task ReportProgressAsync(Action action)
{
return Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}
public Task RegisterContinuation(Task task, Action action)
{
return task.ContinueWith(() => action(), CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}
public Task RegisterContinuation<TResult>(Task<TResult> task, Action action)
{
return task.ContinueWith(() => action(), CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}
应用程序输出窗口中的结果将是:
Start in thread 1
Work in thread 6
Reporting in thread 6 (should be 1)
Work in thread 6
Reporting in thread 6 (should be 1)
...
Result in thread 1 (should be 1)
如您所见,“在线程 6 中工作”很好。报告也在线程 6 上,这是错误的。有趣的是 RegisterContinuation
在线程 1 中进行报告!!!
进展:我还没有想出这个……有人吗?
最佳答案
我认为问题在于您通过执行 TaskScheduler.FromCurrentSynchronizationContext()
从 ProgressReporter 类中检索任务调度程序。
您应该将任务调度器传递给 ProgressReporter 并改用它:
public class ProgressReporter
{
private readonly TaskScheduler taskScheduler;
public ProgressReporter(TaskScheduler taskScheduler)
{
this.taskScheduler = taskScheduler;
}
public Task RegisterContinuation(Task task, Action action)
{
return task.ContinueWith(n => action(), CancellationToken.None,
TaskContinuationOptions.None, taskScheduler);
}
// Remaining members...
}
通过将从 UI 线程获取的任务调度器传递给进度报告器,您可以确定任何报告都是在 UI 线程上完成的:
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
ProgressReporter progressReporter = new ProgressReporter(uiScheduler);
关于c# - 为什么 TaskScheduler.FromCurrentSynchronizationContext 在 Monotouch 中不同步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9773625/
我目前正在处理一个从大型二进制文件读取的应用程序,该文件包含数千个文件,每个文件都由应用程序中的其他类处理。此类返回一个对象或 null。我想在主窗体上显示进度,但出于某种原因我无法理解它。 int
我目前正在处理一个从大型二进制文件读取的应用程序,该文件包含数千个文件,每个文件都由应用程序中的其他类处理。此类返回一个对象或 null。我想在主窗体上显示进度,但出于某种原因我无法理解它。 int
不太确定这里发生了什么- 这段代码会导致问题,因为它首先从主线程调用(在 VS 的任务 View 中验证)并安排任务,但是在 UpdateSearchCache 中设置断点时,我们现在在工作线程中 -
我在尝试运行下面的示例时遇到运行时异常。 Unhandled Exception: System.InvalidOperationException: The current Synchronizat
我在通过任务调用服务的 ViewModel 中有代码。 任务完成后,它将填充 ObservableCollection。 问题是它通过使用 ContinueWith 方法并提供 TaskSchedul
我想使用 Task 将一些文本添加到列表框中,我只需使用一个按钮并在点击事件中放置以下代码: TaskScheduler uiScheduler = TaskScheduler.FromCurrent
在加载 WPF 应用程序时存储/缓存从 TaskScheduler.FromCurrentSynchronizationContext 返回的 TaskScheduler 并从那里开始使用它是否有意义
我正在 VS2012、WPF 和 MVVM 中做一些 TPL。我有一个问题,我想我知道答案但想确定。考虑这个片段: TaskCanceller = new CancellationTokenSourc
我感兴趣的是为什么我们需要调用 InvokeOnMainThread 而这将是 TaskScheduler.FromCurrentSynchronizationContext() 的主要意图和职责?
我有一个从数据库中获取产品的任务,以及操作一些 UI 修改的 ContinueWith 操作,因此我遇到了一个问题,因为任务创建了一个新线程,并且没有执行 UI 修改在 UI 线程中。 我尝试使用此修
我们正在观察一些奇怪的事情,代码如下: var task = new Task(...); // run in the background, do something lengthy work ta
这是 this question 的后续行动. 问题:使用 async 表达以下内容的简洁方式是什么?/await而不是 .ContinueWith() ?: var task = Task.Run(
我是一名优秀的程序员,十分优秀!