Pergunta

I'm having some files that I need to download on app startup (first run). I am using the Background Downloader in windows 8. This is how I use it:

BackgroundDownloader downloader = new BackgroundDownloader();

List<DownloadOperation> operations = new List<DownloadOperation>();
foreach (FileInfo info in infoFiles)
{
    Windows.Storage.ApplicationData.Current.LocalFolder;
    foreach (string folder in info.Folders)
    {
        currentFolder = await currentFolder.CreateFolderAsync(folder, CreationCollisionOption.OpenIfExists);       
    }
    //folder hierarchy created, save the file
    StorageFile file = await currentFolder.CreateFileAsync(info.FileName, CreationCollisionOption.ReplaceExisting);

    DownloadOperation op = downloader.CreateDownload(new Uri(info.Url), file);
    activeDownloads.Add(op);
    operations.Add(op);
}


foreach (DownloadOperation download in operations)
{
  //start downloads
  await HandleDownloadAsync(download, true);
}

When I try to use BackgroundDownloader.GetCurrentDownloadsAsync(); I get only one background download discovered. So I removed the await operator above to get them to start asynchronously.

However I need to know when all files are finished so I can set a progress bar.

I need a way to download multiple files, discover all of them in BackgroundDownloader.GetCurrentDownloadsAsync(); and know when all downloads are completed.

  private async Task HandleDownloadAsync(DownloadOperation download, bool start)
    {
        try
        {
            Debug.WriteLine("Running: " + download.Guid, NotifyType.StatusMessage);

            // Store the download so we can pause/resume.
            activeDownloads.Add(download);

            Progress<DownloadOperation> progressCallback = new Progress<DownloadOperation>(DownloadProgress);
            if (start)
            {
                // Start the download and attach a progress handler.
                await download.StartAsync().AsTask(cts.Token, progressCallback);
            }
            else
            {
                // The download was already running when the application started, re-attach the progress handler.
                await download.AttachAsync().AsTask(cts.Token, progressCallback);
            }

            ResponseInformation response = download.GetResponseInformation();

            Debug.WriteLine(String.Format("Completed: {0}, Status Code: {1}", download.Guid, response.StatusCode),
                NotifyType.StatusMessage);
        }
        catch (TaskCanceledException)
        {
            Debug.WriteLine("Canceled: " + download.Guid, NotifyType.StatusMessage);
        }
        catch (Exception ex)
        {
            if (!IsExceptionHandled("Execution error", ex, download))
            {
                throw;
            }
        }
        finally
        {
            activeDownloads.Remove(download);
        }
    }
Foi útil?

Solução

If you specifically need to re-download the file at every app startup, you shouldn't use BackgroundDownloader - it's intended for scenarios where you need downloads that keep on happening even when your app gets suspended and then restarted. If you're just going to re-download the files again when your app starts up again next time, you're just wasting battery by allowing the downloads to continue once your app goes away.

You have a few options for non-background-capable downloads in a Windows Store app. The most straightforward is Windows.Web.Http.HttpClient - here's a good primer on how to use it. However, it's only available in Windows 8.1 apps, not Windows 8.0. If you need Windows 8.0 compatibility, the distinct but similarly named System.Net.Http.HttpClient is probably the way to go. Harrison already provided a link to the relevant Quickstart documentation.

If you really do want background download capability, please revise your question to more accurately reflect your scenario. It's certainly possible to use BackgroundDownloader to start up several background downloads concurrently and attach progress and completion handlers to each of them, but that doesn't sound like the best solution for the scenario in your question.


Now that you've clarified your usage, the issue is more clear. Your HandleDownloadAsync method is attaching the progress handler you want to the download, but then it's awaiting the completion of that download. When you write

foreach (DownloadOperation download in operations)
{
    //start downloads
    await HandleDownloadAsync(download, true);
}

you are therefore awaiting on the completion of each download in turn before you start the next download.

The solution here is to not await the result of your HandleDownloadAsync calls until after you've performed all of the calls - this will start up each of the downloads immediately and attach the appropriate progress handlers without waiting for any of them to complete. A revised version might look something like this:

BackgroundDownloader downloader = new BackgroundDownloader();

List<Task> downloadCompletionTasks = new List<Task>();
foreach (FileInfo info in infoFiles)
{
    StorageFile file = /* ... */;

    DownloadOperation op = downloader.CreateDownload(new Uri(info.Url), file);

    // Consider moving this line into HandleDownloadAsync so you won't have to repeat
    // it in the code that's handling the GetCurrentDownloadsAsync logic.
    activeDownloads.Add(op);

    // Starting the download, but not awaiting its completion yet
    Task downloadCompletionTask = HandleDownloadAsync(op, true);
    downloadCompletionTasks.Add(downloadCompletionTask);
}

// Now that we've got all the downloads started concurrently, we can wait until all of them complete
await Task.WhenAll(downloadCompletionTasks);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top