【问题标题】: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 被调用了两次(或应用程序从后台转到前台的次数)。

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

【问题讨论】:

    标签: c# ios iphone xamarin.ios xamarin.forms


    【解决方案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.");
    }
    

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-25
      • 2021-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-13
      相关资源
      最近更新 更多