06,Windows Phone 8程序的生命周期


內容預告:

  • 啟動(Launching)和關閉(Closing)
  • Deactviating和Activating
  • Dormant和Tombstoned
  • 用模擬器模擬這些事件
  • 空閑檢測
  • 快速恢復
  • 生命周期規划
  • 頁面導航和后退棧

Windows Phone應用程序在不同的狀態間過渡的圖示如下:

程序從點擊開始屏幕的圖標上啟動,用戶可以關閉程序,系統可能掛起你的程序(在程序失去焦點的時候),掛起的程序可能會進入墓碑,程序可能從掛起狀態激活。
當用戶啟動一個新的程序的實例時,之前的掛起狀態會丟失。比如當運行一個程序時,點到了Home鍵,再點擊開始屏幕的圖標上啟動程序,按Home鍵之前掛起狀態會丟失,正確的做法是按住Back鍵不動選擇那個程序恢復狀態。
在Windows Phone 8中,可以用快速恢復功能(Fast Application Resume)重新啟動掛起的程序。

應用程序的生命周期事件:

private void Application_Launching(object sender, LaunchingEventArgs e)
{
}

Windows Phone應用程序環境會通過一些事件通知上述狀態,在項目模板里的App.xaml里訂閱了事件,並在App.xaml.cs處理了,初使化情況下處理邏輯是空的。

啟動和關閉:Launching 和 Closing
當程序啟動時,Applcation_Launching會被調用,程序結束時,Application_Closing會被調用,調試器在程序停止后還會繼續運行,所以需要手動結束。

程序的Deactivation和Reactivation:
出於省電的考慮,任何時間只有一個程序運行在前台,用戶可以deactivate程序也可以reactivate它們,程序需要處理Activated和Deactivated事件。

程序的休眠(Dormant):
用戶可以隨時休眠應用程序,然后運行其他程序,這個時候Application_Deactivated函數被調用,電話突然打來時,程序也會休眠,鎖屏時程序也會休眠一段時間。用戶也可以恢復休眠的程序。但是不保證一定能從休眠狀態中恢復。

從休眠中重新激活:

處理休眠:
當程序被休眠時必須盡可能地保存數據因為程序可能會關閉,如果用戶不再通過長按Back回到那個程序,Application_Deactivated就相當於Application_Closing了。
你的程序有5秒鍾的機會清理現場(保存數據),之后程序會被從內存中清除掉。當程序長按Back恢復時,它會自動恢復到Deactivated時的那個頁面,這是操作系統幫我們做的,但是,頁面的內容並不會自動保存。

從休眠到墓碑:

一個程序會和其他程序一起在內存里休眠,如果操作系統的內存不夠用了會釋放最先休眠的程序的緩存狀態,這個過程叫做“墓碑化”。
頁面導航歷史和緩存狀態都被墓碑了的程序維護着。
當一個休眠了的程序恢復時,緩存狀態會重新加載,程序會萬利到它離開之前的那個頁面。
當一個墓碑了的程序恢復時,它會重啟離開之前的頁面,但是所有的程序狀態會丟失,你需要重新加載。
一個程序可以決定從哪個狀態激活。

從墓碑狀態重新激活:

 

從休眠還是墓碑恢復的?可以在恢復前做一個判斷

private void Application_Activated(object sender, ActivatedEventArgs e)
{
    if (e.IsApplicationInstancePreserved)
    {
        // Dormant - objects in memory intact
    }
    else
    {
        // Tombstoned - need to reload
    }
}


狀態和墓碑:

當程序從休眠恢復時,程序會准確地恢復到離開時的頁面,所有的對象和它們的狀態都在內存里,你可能需要寫一些邏輯來重置依賴於時間或網絡的調用代碼。
當程序從墓碑恢復時,程序只會恢復到離開時的頁面,但所有對象和它們的狀態都丟失了,所以需要重新加載控件的數據,這就是為什么需要保存狀態,程序從內存中移除了系統也維護着狀態。
當程序的一個新的實例啟動時,狀態是空的。如果一個先前的程序掛起了,那么那個程序存儲的狀態字典會丟失。

狀態字典:

PhoneApplicationService.Current.State["Url"] = "www.robmiles.com";

休眠程序的狀態信息存在一個狀態字典里,如上述代碼。
可以在Application_Deactivated函數里存儲,然后在頁面激活時讀取。
所以Application_Deactivated有兩件事情要做,保存數據以防程序不能重新激活,保存狀態數據以保證程序恢復到正確的狀態。

調試墓碑狀態:

當休眠的時候,可以在Visual Studio里設置強制程序墓碑化(從內存中移除)。
你應該把這個做為測試引擎的一部分。
你也可以用模擬器操作鎖屏,也可以讓程序進入休眠。

 模擬器操作面板:

模擬器可以模擬鎖屏和解鎖,會讓程序進入Deactivated和Activated狀態。

 

空閑處理:
Windows Phone操作系統會檢測到程序的空閑狀態,當手機進入空閑狀態,會讓手機鎖屏。
用戶可以配置多長時間后開始檢測,也可以關閉檢測。
當程序被檢測到是空閑的話,將會進行Deactivated狀態,當用戶解鎖后,手機會Activated。
程序可以禁止檢測空閑,那樣就可以在鎖屏下運行了。

PhoneApplicationService.Current.ApplicationIdleDetectionMode =  IdleDetectionMode.Disabled;

這樣即使手機鎖屏了也會有什么Activated和Deactivated了。
但如果是用戶按了Start鍵還是會deactivated。
禁止空閑檢測也不能同時運行兩個程序。

檢測遮擋事件:比如toast消息,鎖屏,來電等。

App.RootFrame.Obscured += RootFrame_Obscured;

...

void RootFrame_Obscured(object sender, ObscuredEventArgs e)
{
}

程序可以訂閱遮擋事件,也可以訂閱遮擋移除的事件。

導航和后退棧:

Windows Phone程序的導航模型使用起來很方便,可以通過鏈接到其他頁面,可以通過后退鍵到上一個頁面。
系統維護了一個后退的棧,當跳轉到另一個頁面時,之前的頁面地址會被壓入棧,當后退時,當前頁面會出棧。

后退棧和Activated/Deactivated:

當程序deactivated時,系統會保持后退棧,包括當前的頁面,但只有頁面地址被保存,內容並不保存。
程序必須在OnNavigatedTo和OnNavigatedFrom事件里構建頁面和保存數據。

從不同的地方進入程序:

一般情況下程序會在運行時顯示首頁,而且這個首頁會被壓入棧,且后退時會回到首頁。
有些情況下可以不用進入首頁,比如(第二磁貼,提醒,文件關聯,搜索,錢包,語音),但同時帶來新的問題

后退棧的問題:

有這樣一個場景,當用戶在后退棧里憶壓入很多頁面時,進入相冊選擇了相片,然后在相冊界面按后退鍵,會首先回到程序進入相冊前的最后一個頁面,再后退,程序會退出。
這里需要特殊處理后退棧,比如模擬后退棧,因為在頁面從后退棧清除時會有一個事件觸發。

模擬后退棧:

private void PurgeBackStackButton_Click(object sender, RoutedEventArgs e)
{
    while (NavigationService.CanGoBack)
        NavigationService.RemoveBackEntry();
}

程序可以質問后退棧是否可以后退,也可以把棧內所有頁面清除光。
程序可以枚舉后退棧的所有頁面,但不能將頁面壓棧。

OnRemovedFromJournal:

protected override void OnRemovedFromJournal(JournalEntryRemovedEventArgs e)
{
    base.OnRemovedFromJournal(e);

}

在程序運動時,一個頁面希望能夠從子頁面返回,但如果它從后退棧移除后就不是這個流程了。
可以用OnRemovedFromJournal事件捕獲當本頁面從后退棧里移除時做一些處理。

快速恢復FAR(Fast Application Resume):這個功能可以讓程序在激活時速度更快。需要手動在WMAppManifest.xml里編輯

<Tasks>
    <DefaultTask  Name ="_default" NavigationPage="MainPage.xaml">
      <BackgroundExecution>
        <ExecutionType Name="LocationTracking" />
      </BackgroundExecution>
    </DefaultTask>
</Tasks>

FAR的兩種下場:
通過把程序注冊為LocationTracking可以實現FAR,但LocationTracking我們未必會用。

如果程序中用到了定位的類,那么當程序deactivated時會繼續一直在后台運行,如果重新運行程序,程序會快速從當前休眠的狀態恢復。

如果程序中沒用定位的類,那么那么當程序deactivated時,程序像平常一樣,如果重新運行程序,程序會從之前休眠的狀態恢復。

 

標准的重新啟動程序如上圖所示:

真正的有后台定位的行為如上圖所示:

后台無定位程序在運行的FAR程序如上圖所示:

為什么不在所有程序上用FAR?

因為用的時候要非常小心頁面導航的用戶體驗,
非FAR的程序中,如果啟動程序到page2,那么page2是后退棧里唯一的頁面,按后退會退出程序。
在FAR的程序中,如果啟動程序到page2,但是之前掛起的程序的后退棧里有mainpage,page1,page2,page3,那么當運行新程序實例時,按后退鍵的話,程序會以mainpgae,pgae1,page2,page3,page2的程序退出。

FAR程序中主磁貼的行為:

用戶在點擊程序的磁貼后,程序會進入主頁面,非FAR的程序會這樣,之前沒有掛起實例的FAR的程序也會這樣。
如果是恢復到程序呢?應該是怎么樣?恢復到首頁還是最后一個頁面?如果恢復到最后一頁那怎么進入首頁?這里有一個建議是在頁面上加一個回到首頁的鏈接。

檢測FAR程序的恢復行為:

在真正的有后台運行定位的程序中,當程序被送到后台后會繼續運行,程序會觸發PhoneApplicationService.RunningInBackground事件而不是Application_Deactivated事件。
當FAR程序重新啟動時,會以
NavigationMode.Reset的方式導航到后退棧最頂部的頁面,然后會以NavigationMode.New的方式定位到新啟動的URL的頁面,可以決定是否上傳頁面的后退棧,或取消導航到新頁面。

清除FAR程序之前的實例運行的頁面:在App.xaml.cs里加入

 

 
         

private void InitializePhoneApplication()
 {
     ...
     // Handle reset requests for clearing the backstack
     RootFrame.Navigated += CheckForResetNavigation;

 
         

     ...
 }

 private void CheckForResetNavigation(object sender, NavigationEventArgs e)
 {
     // If the app has received a 'reset' navigation, then we need to check
     // on the next navigation to see if the page stack should be reset
     if (e.NavigationMode == NavigationMode.Reset)
         RootFrame.Navigated += ClearBackStackAfterReset;
 }

 private void ClearBackStackAfterReset(object sender, NavigationEventArgs e)
 {
     // Unregister the event so it doesn't get called again
     RootFrame.Navigated -= ClearBackStackAfterReset;
     // Only clear the stack for 'new' (forward) and 'refresh' navigations
     if (e.NavigationMode != NavigationMode.New && e.NavigationMode != NavigationMode.Refresh)
         return;
     // For UI consistency, clear the entire page stack
     while (RootFrame.RemoveBackEntry() != null)   { } // do nothing  
 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM