2016-09-26 63 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."); 
} 

希望它能幫助你。

相關問題