2016-07-16 51 views
0

我正在開發一個Xamarin Forms應用程序,但我不認爲我的問題是Xamarin特定的。 用戶輸入PIN碼後(當然只有PIN碼是正確的),我給他看標籤頁。每個頁面都有一些控件,但更重要的是,每個頁面都必須使用異步調用從Web獲取一些數據。現在,由於我的應用程序有幾個選項卡,我想爲它們中的每一個並行(非連續)提取所有數據。我到目前爲止所實現的,是這樣的:如何在後臺準備應用程序數據?

public MainTabbedPage(bool requirePin) 
    { 
     if (requirePin) 
     { 
      Navigation.PushModalAsync(new PinEntryPage(this)); 
     } 
     InitializeComponent(); 

    } 

    public void InitializeChildren() 
    { 
     try 
     { 
      var page1 = new Page1(); 
      page1.RefreshData(); 

      var page2 = new Page2(); 
      page2.RefreshButtons(); 
      page2.RefreshData(); 

      var page3 = new Page3(); 
      page3.RefreshData(); 

      Children.Add(page1); 
      Children.Add(page2); 
      Children.Add(page3); 
     } 
     catch (Exception ex) 
     { 
      // some error handling... 
     } 
    } 

而所有RefreshData()RefreshButtons()是這樣的:現在

public void RefreshData() 
    { 
     Task.Run(
      () => 
      { 
       var data = ApiSingleton.Instance.GetData().Result; 
       // some data manipulations 
       Device.BeginInvokeOnMainThread(() => /* some UI manipulation*/); 
       } 
      }); 
    } 

,而這似乎是在做正確的,我不知道這是一個正確的這樣做的方式,如果沒有,是什麼?

+1

'GetData()'似乎是一個任務。所以你可以簡單地等待他的結果,在'RefreshData'異步之後。不需要'Task.Run()'imo – lokusking

+1

'GetData()'看起來像一個異步方法(因爲你觸摸'Result'),所以爲什麼不真正地讓整個鏈正確異步並且不要亂丟任務? –

+0

確實是異步的,謝謝。順便說一句,這意味着我不需要'Device.BeginInvokeOnMainThread',對吧? – nicks

回答

1

做這樣的:

public MainTabbedPage(bool requirePin) 
{ 
    if (requirePin) 
    { 
     Navigation.PushModalAsync(new PinEntryPage(this)); 
    } 
    InitializeComponent(); 
} 

public async void InitializeChildren() 
{ 
    try 
    { 
     var page1 = new Page1(); 
     await page1.RefreshData(); 

     var page2 = new Page2(); 
     await page2.RefreshButtons(); 
     await page2.RefreshData(); 

     var page3 = new Page3(); 
     await page3.RefreshData(); 

     Children.Add(page1); 
     Children.Add(page2); 
     Children.Add(page3); 
    } 
    catch (Exception ex) 
    { 
     // some error handling... 
    } 
} 

而對於方法刷新方法:

public async Task RefreshData() 
{ 
    var data = await ApiSingleton.Instance.GetData(); 
    // some data manipulations 
    // you are on the UI thread here 
    // so there is no nead for BeginInvokeOnMainThread  
} 

作爲替代加快東西你可能想立刻開始對所有頁面的數據referesh 。如果這是你想要的東西,改變InitializeChildren到這樣的事情:

public async void InitializeChildren() 
{ 
    try 
    { 
     var page1 = new Page1(); 
     var refreshPage1Task = page1.RefreshData(); 

     var page2 = new Page2(); 
     var refreshButtonsPage2Task = page2.RefreshButtons(); 
     var refreshPage2Task = page2.RefreshData(); 

     var page3 = new Page3(); 
     var refreshPage3Task = page3.RefreshData(); 

     await Task.WhenAll(new Task[] { 
      refreshPage1Task, refreshPage2Task, 
      refreshPage3Task, refreshButtonsPage2Task }); 

     Children.Add(page1); 
     Children.Add(page2); 
     Children.Add(page3); 
    } 
    catch (Exception ex) 
    { 
     // some error handling... 
    } 
} 

這將立即開始在所有頁面的刷新,所以網絡操作可以同時運行。每次調用後返回到UI線程仍會發生。 Task.WhenAll將確保僅在所有刷新操作完成後纔將頁面附加到Children集合。

+0

在將頁面添加到頁面之前如何等待子頁面被初始化會加快速度? – nicks

+0

此外,在用戶提供正確的引腳之前開始讀取數據對我來說聽起來並不好......你認爲沒關係嗎?它安全嗎? – nicks

+1

我想GetData方法正在做某種數據訪問。這意味着當數據從磁盤或從網絡加載時,其他任務已經可以開始。假設網絡請求需要1秒才能完成 - 那麼原始代碼需要3秒才能完成,但併發版本需要一秒多一點的時間,因爲所有請求都會同時運行。 –

相關問題