[UWP]后台任务在约10-20分钟后终止(下载文件)

时间:2016-04-19 13:24:26

标签: c# .net mobile win-universal-app background-transfer

我在UWP APP中同步文件。我正在使用后台任务和ApplicationTrigger。如果我调试我的代码(我的意思是如果附加调试器)它可以工作,但如果我运行已安装的应用程序,后台任务将在10-20分钟后终止。 我必须同步很多文件,需要1-2小时(我知道这很疯狂)。 我在这里找到了一个信息: https://msdn.microsoft.com/en-us/windows/uwp/launch-resume/handle-a-cancelled-background-task,但我不确定是不是这样,因为所有内存都没问题。

“注意对于除桌面以外的所有设备系列,如果设备内存不足,后台任务可能会终止。如果内存不足异常没有浮出水面,或者应用程序没有处理它,那么后台任务将是在没有警告且没有提升OnCanceled事件的情况下终止。这有助于确保应用程序在前台的用户体验。您的后台任务应该设计为处理这种情况。“

    public async void Run(IBackgroundTaskInstance taskInstance)
    {
        deferral = taskInstance.GetDeferral();
        _taskInstance = taskInstance;

        var details = taskInstance.TriggerDetails as ApplicationTriggerDetails;

        IEnumerable<string> filesUrls = details.Arguments.Select(x => x.Value as string).Distinct().ToList();
        filesCount = filesUrls.Count();

        downloader = CompletionGroupTask.CreateBackgroundDownloader();

        var result = await Download(filesUrls, taskInstance, downloader);
        if (result)
        {
            await Download(failedDownloads, taskInstance, downloader);
        }
        downloader.CompletionGroup.Enable();
        deferral.Complete();
    }

    private async Task<bool> Download(IEnumerable<string> filesUrls, IBackgroundTaskInstance taskInstance, BackgroundDownloader downloader)
    {
        bool downloadFailed = false;
        failedDownloads = new List<string>();
        foreach (string url in filesUrls)
        {
            DownloadOperation download = null;
            var uri = new Uri(url);
            try
            {
                download = downloader.CreateDownload(uri, await CreateResultFileAsync(url.Split('/').Last()));
                Task<DownloadOperation> startTask = download.StartAsync().AsTask();
                await startTask.ContinueWith(task => OnDownloadCompleted(task, url));
            }
            catch
            {
                downloadFailed = true;
                failedDownloads.Add(url);
            }
        }
        return downloadFailed;
    }


    private void OnDownloadCompleted(Task<DownloadOperation> task, string url)
    {
        if (task.Status == TaskStatus.RanToCompletion)
        {
            completedDownloads++;
            decimal progress = (completedDownloads / filesCount) * 100;
            _taskInstance.Progress = Convert.ToUInt32(progress);

        }
        else if(task.Status == TaskStatus.Faulted)
        {
            failedDownloads.Add(url);
        }
    }

    private async Task<IStorageFile> CreateResultFileAsync(string fileName)
    {
        var local = ApplicationData.Current.LocalFolder;
        IStorageFile resultFile = await local.CreateFileAsync(fileName, CreationCollisionOption.FailIfExists);
        return resultFile;
    }
}

有谁知道为什么我的任务被杀?

2 个答案:

答案 0 :(得分:2)

针对创作者的更新进行了更新

现在有一个名为extendedBackgroundTaskTime的受限功能,可用于使后台进程在需要时运行1到2个小时。它不会被Windows Store接受,但适用于侧载的业务线应用程序并提交到Windows Store for Business:https://docs.microsoft.com/en-us/windows/uwp/packaging/app-capability-declarations

目前还没有方法可以为提交到商店的应用运行1小时到2小时的真正无头背景同步。这种类型的同步可以异步完成并以块的形式完成。 BackgroundUploader和BackgroundDownloader类是用于执行单个文件的网络传输的选项,然后根据每个文件的下载完成情况被唤醒以执行工作。如果同步可以等到设备处于交流连接状态,则还可以注册维护触发器以定期唤醒并运行10分钟以进行一系列同步工作。

如果您的应用程序可以位于前台并且最小化,那么扩展执行未指定可能是一个不错的选择。它也具有电池感知功能,但如果他们的应用程序处于交流连接状态并且没有尝试进入连接待机状态,那么它可以无限期运行。此方法通常用于具有多任务处理的媒体或其他项目编译活动,但可能是您可以采用的方法。

答案 1 :(得分:1)

使用BackgroundTaskCancellationReason = ExecutionTimeExceeded 取消后台任务,因为如果应用程序正在运行,运行ApplicationTrigger的后台任务所允许的最长时间为10分钟。如果应用程序暂停,则允许使用ApplicationTrigger的后台任务最多运行5分钟。如果达到此时间限制,操作系统将使用BackgroundTaskCancellationReason = IdleTask 取消任务。

在后台任务中,将此代码放在Run方法的开头,以便在toast中查看取消原因。

        taskInstance.Canceled += (s, e) => {
            var toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText01);
            var toastTextElements = toastXml.GetElementsByTagName("text");
            toastTextElements[0].InnerText = e.ToString();
            ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(toastXml));
        };