应用进入后台时任务取消

Posted

技术标签:

【中文标题】应用进入后台时任务取消【英文标题】:Task Cancellation when app enters background 【发布时间】:2016-09-26 08:54:41 【问题描述】:

我正在研究 xamarin 表单 PCL + ios。我想在任务进入后台时取消它。并在应用程序进入前台时重新开始。

这是我迄今为止尝试过的。我不确定我的方式是否取消了任何任务或者这里发生了什么?

async void getData()

bool isSuccess = await getSomeData();

if(isSuccess)
await getSomeMoreData();


CancellationTokenSource cts;

async Task<bool> getSomeData()

cts = new CancellationTokenSource();

AppEntersBackgorund += (sender,args) =>  cts. cancel(););

CancellationToken token = new CancellationToken();
token = cts.token;

await Task.Run(() => 
token.ThrowIfCancellationRequested();
isSuccess = ParserData(token); // parsedata also checks periodically if task is cancelled
,token); //what happens here when cancel called?

return isSuccess;


async void getSomeMoreData()

if(!cts.IsCancellationRequested)
 cts = new CancellationTokenSource();

AppEntersBackgorund += (sender,args) =>  cts. cancel(););

CancellationToken token = new CancellationToken();
token = cts.token;

await Task.Run(() =>

token.ThrowIfCancellationRequested();
ParseSomeMoreData(token);
,token);


当应用程序进入前台时,我再次调用 getData() 方法,以便重新开始。

发生的情况是,Task 没有被取消,而是 getSomeMoreData 被调用了两次(或应用程序从后台转到前台的次数)。

有人可以解释我如何实现这一目标吗?这里发生了什么?

【问题讨论】:

【参考方案1】:

其实这不是 Xamarin 的问题,只是 C# 的问题,除了应用程序的进入前台/后台事件。

对于你需要的需求,你应该做一个任务管理器对象来实现它。

我为你写了一个示例代码:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading;

namespace BackGroundTask

    public class TaskManager
    
        //The instance property
        private static TaskManager instance;
        public static TaskManager Instance
            get
                if(null == instance)
                    instance = new TaskManager();
                return instance;
            
        

        private bool actionTaskFreeFlag = true;//Flag for if actionTask is available or not

        private Queue<Action> taskQueue;//A queue to collect the tasks you added into the manager
        private Task scanTask;//A Task to sacn the queue
        private Task actionTask;//A task to do the current action
        private Thread actionTaskRunningThread;//Record the thread that current action is working on 

        public TaskManager()
        
            taskQueue = new Queue<Action>();

            scanTask = new Task(() =>
            
                while (true)
                
                    if (actionTaskFreeFlag && taskQueue.Count > 0)//If there still something to do and the actionTask is available then do the action
                    
                        actionTaskFreeFlag = false;
                        Action action = taskQueue.Dequeue();
                        actionTask = new Task(() => 
                            actionTaskRunningThread = System.Threading.Thread.CurrentThread;
                            action();
                        );
                        actionTask.Start();
                        actionTask.ContinueWith(delegate 
                            actionTaskFreeFlag = true;
                        );
                    
                
            );
            scanTask.Start();
        

        public void AddAction(Action action) 
        
            taskQueue.Enqueue(action);
        

        public void CancelCurrentTaskAndClearTaskQueue()
        
            Console.WriteLine("CancelCurrentTaskAndClearTaskQueue");
            if(null != actionTaskRunningThread)
                actionTaskRunningThread.Abort();
            taskQueue.Clear();
        
    

这是一个示例代码,说明如何使用它来做你想做的事情:

//App enter background event
AppDelegate.Instance.AppDidEnterBackground += delegate 
    TaskManager.Instance.CancelCurrentTaskAndClearTaskQueue();
;
//App enter forcenground event
AppDelegate.Instance.AppWillEnterForeground += delegate 
    if (AppDelegate.FlagForGetData)
    
        TaskManager.Instance.AddAction(GetData);
        TaskManager.Instance.AddAction(GetMoreData);
    
;

这是测试的方法:

private void GetData()

    AppDelegate.FlagForGetData = true;
    Console.WriteLine("Began getting data.");
    System.Threading.Thread.Sleep(5000);
    AppDelegate.FlagForGetData = false;
    Console.WriteLine("Getting data succeed.");


private void GetMoreData()

    Console.WriteLine("Began getting more data.");
    System.Threading.Thread.Sleep(3000);
    Console.WriteLine("Getting more data succeed.");

希望对你有帮助。

【讨论】:

以上是关于应用进入后台时任务取消的主要内容,如果未能解决你的问题,请参考以下文章

当应用程序进入暂停状态时取消本地通知。(从后台删除)

如何取消我恢复的 NSURLSessionDownloadTask 以恢复我上次启动应用程序时创建的下载(后台)任务

当 iOS 应用程序进入后台时,是不是会暂停冗长的任务?

当应用程序进入后台时,在前台执行的长时间运行的任务被挂起

iOS - 当应用程序在后台时取消蓝牙连接

进入后台时的 NSURLConnection 最佳实践