10

使用后台传输 API 时,我们必须遍历当前数据传输以在应用程序在终止(即系统关闭)后重新启动时再次启动它们。要获取进度信息并能够取消数据传输,必须使用 AttachAsync 附加它们。

我的问题是 AttachAsync 仅在数据传输完成时返回。这在某些情况下是有道理的。但是当有多个数据传输时,列表中的下一个传输将不会开始,直到当前附加完成。我对这个问题的解决方案是处理 AttachAsync().AsTask() 以经典方式返回的任务(不使用等待,而是继续):

IReadOnlyList<DownloadOperation> currentDownloads =
   await BackgroundDownloader.GetCurrentDownloadsAsync();
foreach (var downloadOperation in currentDownloads)
{
   Task task = downloadOperation.AttachAsync().AsTask();

   DownloadOperation operation = downloadOperation;
   task.ContinueWith(_ =>
   {
      // Handle success
      ...
   }, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion,
   TaskScheduler.FromCurrentSynchronizationContext());

   task.ContinueWith(_ =>
   {
      // Handle cancellation
      ...
  }, CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled,
  TaskScheduler.FromCurrentSynchronizationContext());

  task.ContinueWith(t =>
  {
     // Handle errors
      ...

  }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted,
  TaskScheduler.FromCurrentSynchronizationContext());
}

它有点工作(在实际代码中,我将下载添加到 ListBox)。该循环遍历所有下载并执行 StartAsync。但是下载并不是同时开始的。一次只有一个在运行,并且只有在它完成时才会继续下一个。

这个问题有什么解决办法吗?

4

2 回答 2

3

的重点Task是让您可以选择并行操作。如果您await是在告诉代码序列化操作;如果您不等待,那么您就是在告诉代码并行化。

您可以做的是将每个下载任务添加到列表中,告诉代码并行化。然后,您可以一项一项地等待任务完成。

怎么样:

IReadOnlyList<DownloadOperation> currentDownloads = 
    await BackgroundDownloader.GetCurrentDownloadsAsync();
if (currentDownloads.Count > 0)
{
    List<Task<DownloadOperation>> tasks = new List<Task<DownloadOperation>>();
    foreach (DownloadOperation downloadOperation in currentDownloads)
    {
        // Attach progress and completion handlers without waiting for completion
        tasks.Add(downloadOperation.AttachAsync().AsTask());
    }

    while (tasks.Count > 0)
    {
        // wait for ANY download task to finish
        Task<DownloadOperation> task = await Task.WhenAny<DownloadOperation>(tasks);
        tasks.Remove(task);

        // process the completed task...
        if (task.IsCanceled)
        {
            // handle cancel
        }
        else if (task.IsFaulted)
        {
            // handle exception
        }
        else if (task.IsCompleted)
        {
            DownloadOperation dl = task.Result;
            // handle completion (e.g. add to your listbox)
        }
        else
        {
            // should never get here....
        }
    }
}
于 2012-12-28T00:13:07.627 回答
0

我希望这还不算晚,但我确切地知道你在说什么。我还尝试在应用程序启动时恢复所有下载。

经过数小时的尝试,这是可行的解决方案。

诀窍是在攻击进度处理程序之前让下载操作首先恢复。

downloadOperation.Resume();
await downloadOperation.AttachAsync().AsTask(cts.Token);
于 2019-02-21T04:47:57.360 回答