2016-09-26 120 views
0

我正在使用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); 

} 

当应用程序进入foregorund,我再次调用getData()方法,这样我从头再来。

发生什么事是,任务没有被取消,而是getSomeMoreData被调用两次(或应用程序从背景到前景的次数)。

有人可以解释我怎么能做到这一点?这里发生了什么?

回答

0

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

希望它能帮助你。

相关问题