当应用程序进入后台时任务取消

本文关键字:任务 取消 后台 应用程序 | 更新日期: 2023-09-27 18:08:43

我正在研究xamarin表单PCL + iOS。我想在任务进入后台时取消它。然后在app进入前台时重新开始。

这是我到目前为止所尝试的。我不确定我的方式是否取消了任何任务,或者这里发生了什么?

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()方法,以便我重新开始。

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

有人能解释一下我怎么才能做到这一点吗?这里发生了什么?

当应用程序进入后台时任务取消

实际上,这不是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.");
}

希望对你有帮助