Windows Phone 7 – Runing App under the Locked Screen詳述
在老狗分享了<Running a Windows Phone Application under the lock screen>這一篇關於如何讓開發出來的App可以在
Locked Screen情形下還能繼續執行,讓我覺得非常有趣而且也帶進了很多觀念,所以我想把它做個更詳細的說明,
協助我自己在閱讀上更能快速掌握。
先強調一個觀念,所謂的支援Locked Screen下的運作:
「目前App正在執行,按下了Locked Screen的任務;或者是App在執行一段時間後,手機自動進入Locked Screen任務。」
這個是要先釐清的部分,支援的功能不是App在執行按了Windows鍵或Back鍵還能Work的情形。
[註]
該篇文章的內容,透過WP7 Emulator的測試其實感覺不太出來,建議如果你有WP7設備的話,測試比較會有感覺。
另外,也許你可以修改WP7 Emulator檔案來取得設定關閉螢幕的時間,也許這樣會有不錯的測試效果。
在說明WP7支援App跑在Locked Screen下之前,還是要再一次提到關於原本WP7對於App運作生命週期的定義:
〉基本WP7 App的生命週期
之前在<Windows Phone 7-儲存目前Application狀態的主要方法> 一文中,有提到整個WP7 App的LifeCycle,大家可以參考。
而整個LifeCycle裡,重點在於:WP7的App在執行階段,將會随著用戶點選Back鍵、Start鍵、進入Locked Screen或涉及啟動
其他Lanucher、Chooser,將目前App進行Closing或是Tombstoning。這二者處理的不同將會影響程式內容與用戶操作的習慣。
〉運行在Locked Screen下的WP7 App生命週期
由上述WP7 App的生命週期得知進入Locked Screen模式,App會自動進入tombstoning,然而App就被暫時停止了。
所以要支援Locked Screen下運作的App,主要一個重點是:它不再執行tombstoning。 也就是說,它跳過了Deactived Event的流程。
然而,讓App不進入Deactived Event處理,這就表示在Locked Screen下App仍然使用與Unlocked Screen下相同的記憶體與資源,
但其實這樣是不必要的,因此,在進入Locked Screen後除了要讓App可以Work,另一個重點就是能有效節省資源的使用量。
根據<Running a Windows Phone Application under the lock screen>所提到幾項關鍵技術即可以完成在Locked Screen下運作:
(1) 設定PhoneApplicationService.Current.ApplicationIdleDetectionMode = IdleDetectionMode.Disabled
(2) 處理App的RootFrame中二個重要事件:Obscured與Unobscured,分別處理Locked和Unlocked的任務
以下將分別說明:
-關鍵屬性:「PhoneApplicationService.Current.ApplicationIdleDetectionMode = IdleDetectionMode.Disabled」
‧PhoneApplicationService (Microsoft.Phone.Shell)
該類別任務在管理整個應用程式生命週期中各種方面的情形,包括:管理應用程式閒置(idle)時的行為、應用程式的狀態(state)的管
理(例如:應用程式的Launching、Closing、Activated、Deactived)…等,並且它控制整個App運作的屬性與事件。該類別的使用,可
以在專案中的「App.xaml.cs」中常看到。其中PhoneApplicatoinService有幾個非常重要的屬性:
名稱 | 描述 |
ApplicationIdleDetectionMode | 設定/取得應用程式閒置檢測是否啟動。Enabled該屬性,當App進入Idle模式時,作業系統會deactive idle applicatoin。Disabled該屬性,則代表系統不會執行Enabled該作的事,這將會影響電池的使用量與效能。 使用該屬性要特別注意,因為即便進入Locked Screen下,App仍會消耗設備的電池。 更詳細可以參考Idle Detection for Windows Phone。 使用的值是:IdleDetectionMode列舉。 |
Current (*) | 取得PhoneApplicationService物件與當前的App實體。 通常該PhoneApplicatoinService物件與App實體都是由WP7 OS自動產生的,所以控制的機會比較少,但關於Locked Screen下的運作,如何控制目前的PhoneApplicatoinService物件與實體就很重要。 更詳細可參考Execution Model Best Practices for Windows Phone。 |
StartupMode | 取得目前App啟動的模式。由於App啟動的模式可能來自Start按鍵後啟動或執行App之間的互相呼叫等,而通常會被使用由XNA-based的App,因為它們需要監測程式是在Activated或Launching event被觸發前後要進行內容或動作的轉換。 |
State | Dictioncary物件,用於儲存當App進入Deactived event時,把目前App的資訊與內容暫存起來,等到回到Activated evetn在轉出來。 |
UserIdleDetectionMode | 設定/取得用戶閒置檢測是否啟動。Enabled該屬性,當用戶閒置一段時間後,系統自動降低該App使用的資源與運作效能;相反Disabled該屬性就不會執行上述的任務。 然而會使用Disabled的值,通常是在設計遊戲上會使用,因為用戶可能停止一段時間不操作手機(例如:等待下載、loading、動畫等)。更詳細可以參考Idle Detection for Windows Phone。 使用的值是:IdleDetectionMode列舉。 |
從以上的四個屬性的說明,不難看出這次要實作的Locked Screen下繼續運作的App該用的屬性有那些了吧。沒有錯,就是最複雜的
「Current」屬性。由於Current屬性本身代表就是一個PhoneApplicatoinService實例後的物件,所以它也具有以上四個重要的屬性。
為了支援讓App在Locked Screen情形下仍然可以運作,就必須設定:「ApplicationIdleDetectionMode=IdleDetectionMode.Disabled」,
設定為Disabled之後,WP7 OS本身就不會自動在App進入Idle時,把App自動觸發Deactived Event而變成Tombstone。這樣一來,程式可以繼續
執行,但程式如何結束與需要處理資源與效能的動作,變成要由開發人員來負責。
但要先注意一件事情,「ApplicationIdleDetectionMode被設定為Disabled時,沒有辦法把目前執行下轉回Enabled,需要重新啟動
該App才有辦法設定(也就是PhoneApplicationFrame被初始化之後),否則會出現InvalidOperationException例外」。
另外,介紹二個用到的屬性與類別:
成員名稱 | 描述 |
Enabled | UserIdleDetectionMode:當一陣子Touch Event沒有觸發,系統將會考慮將App轉入Idle。 ApplicationIdleDetectionMode:當Lock screen被觸發,系統將自動暫停App的活動。 |
Disabled | UserIdleDetectionMode:當一陣子Touch Event沒有觸發,系統將不會考慮將App轉入Idle。 ApplicationIdleDetectionMode:當Lock screen被觸發,正在執行的App將持續執行。 |
‧PhoneApplicationFrame (Microsoft.Phone.Controls)
由於WP7主要是以Silverlight頁面模式運作,用戶可以透過NavigationService來瀏覽不同Page中的內容,然而,其頁面模式的主要核心內容是
由一個Top-level的容器控件:PhoneApplicatoinFrame來管理Page的處理與瀏覽,另外它更可以控制PhoneApplicationPage控件。更詳細相關頁
頁模式的運作可以參考:Frame and Page Navigation Overview for Windows Phone。
PhoneApplicationFrame管理目前App所有Page,因此,當Locked Screen被啟動時,其實App被影響的就是Page中的內容與事件將會無法使用,
它類似在App上多加了一層薄膜(Locked程式)覆蓋了原App上的Page,但是App上的PhoneApplicatoinFrame是有支援事件可以處理Locked Screen
所帶來的觸發事件。以下,將介紹二個重要的Event Handler,處理App進入Idle時的觸發事件(Obscured)與由Idle進入App時觸發事件(Unobscured)。
-監測事件:「Obscured」與「Unobscured」
‧Obscured / ObscuredEventArgs (EventHandler<ObscuredEventArgs>)
當Sell Chrome覆蓋在Frame上時,觸發該事件。舉例來說:應用程式接收到Locked Screen事件時觸發。
在Locked Screen下支援執行,代表App本身沒有停止,只是上方多蓋了一個Shell Chrome,在這個時候你是沒有辦法操作App畫面上的功能,
所以建議可以把一些相關UI的特效、動畫、網路連接(如果是Download功能的程式例外)等功能停止,降低手機電池的使用。
‧Unobscured / EventArgs
當Shell Chrome不再覆蓋在Frame上時,觸發該事件。舉例來說:當Locked Screen回到應用程式時觸發。
由Locked Screen回到App時,蓋在上面的Shell Chrome會消失,那麼在Locked Screen時被停止的App上UI與功能都要被恢愎回來。
-------------------
以上提到的PhoneApplicationService、PhoneApplicatoinFrame類別與Obscured、Unobscured事件處理都是要完成讓App可支援在Screen鎖定下,
仍可以繼續執行的主要元素。
接著往下將簡單介紹相關實作的程式碼:
‧設定PhoneApplicationService.Current.ApplicationIdleDetectionMode與註冊Obscured、Unobscured事件的處理。
1: if ( runsUnderLock )
2: {
3: //設定目前App的IdleDetectionMode=Disabled,讓WP7 OS不會將程式轉成tombstone
4: PhoneApplicationService.Current.ApplicationIdleDetectionMode = IdleDetectionMode.Disabled;
5:
6: //取得RootVisual,用來註冊Obscured與Uobscured事件處理,客製App在Locked與Unlocked下要完成的任務
7: PhoneApplicationFrame rootframe = App.Current.RootVisual as PhoneApplicationFrame ;
8:
9: System.Diagnostics.Debug.Assert(rootframe != null, "This sample assumes RootVisual has been set");
10: if (rootframe != null)
11: {
12: rootframe.Obscured += new EventHandler<ObscuredEventArgs>(rootframe_Obscured);
13: rootframe.Unobscured += new EventHandler(rootframe_Unobscured);
14: }
15:
16: }
17: else
18: {
19: IsRestartRequired = true;
20: // we can not set it; we have to restart app ...
21: // PhoneApplicationService.Current.ApplicationIdleDetectionMode = IdleDetectionMode.Enabled ;
22: // 此段說明由於IdleDetectionMode不能在App執行時改變,因此,會另外啟動一個EventHandler要求重啟程式。
23: EventHandler eh = RestartRequired;
24: if (eh != null)
25: eh(this, new EventArgs());
26: }
上述程式是擷取出<Running a Windows Phone Application under the lock screen>一文中:ApplicationIdleModeHelper.cs類別裡的部分程式,
用途在於:
(1) 隨著RunsUnderLock屬性值的設定,識別runsUnderLock變數是否App要設定為IdleDetectionMode.Disabled;
如果是則設定;否則則通知要重新啟動程式;
(2) 設定完畢之後,將設定值會被儲存於IsolatedStorage中。
(3) 在下次在App啟動時,將儲存於IsolatedStorage中的Setting取出,進行識別再重新設定RunsUnderLock屬性。
最後,更詳細的範例內容,可以參考<Running a Windows Phone Application under the lock screen>一文中所提供的範例說明,
其範例透過Pivot來呈現二個不同的執行方式:
‧在”greedy pivot”下
說明PhoneApplicationService.Current.ApplicationIdleDetectionMode設定Enabled與Disabled後,App在Locked下可以正常播放音樂;
‧在”mellow pivot”下
透過Obscured與Unobscured事件實作,說明即使支援”Run under lock”,在進入Locked後,音樂還是被關閉了,但等你Unlocked時,
音樂又自動播放了。強調如何實作在Locked下把App的功能暫時停止(不是進行tombstone"),目的在節省電池與效能的消耗。
[補充]
往下我補充在閱讀程式時,遇到一些缺少的觀念,所以在此先補足一些額外在開發上要注意與可以思考的部分:
INotifyPropertyChanged屬於:System.ComponentModel,這個類別常出現在針對客製出來的元件需要實作它背後屬性異動時觸發通知動作
一定會實作的重要介面。如果你有參考過<Silverlight 4商業級應用程式開發>這本書,它裡面幾個範例也有使用該介面來實作擷取指定屬
性變數的處理。實作該介面有什麼好處?
‧連動效果:INotifyPropertyChanged最常用於Data Bind時,處理一個控制項的資料與影響下一個控制項的情形。
‧自動反應:支援該類別的物件或類別,只要實作該介面後在資料的處理上,都會自動反應在對應的控件屬性上。
既然INotifyPropertyChanged有處理Data Bind讓資料異動時,App知道如何去更動UI上的內容,那該實作那些東西呢?
‧PropertyChangedEventHandler
該Event Handler是INotifyPropertyChanged必要實作的事件處理。它的任務通常用於往上通知某一項指定的屬性被Modify了。
當控制項接獲到通知時,就會進行Bind Data的處理來因應屬性調整後的結果。
實作範例可以參考:Bind Better with INotifyPropertyChanged。
‧更詳細的INotifyPropertyChanged的內容
我推薦<View Models: POCOs versus DependencyObjects>這一篇也蠻適合閱讀,裡面有提到ViewModel的定義與應用,
並且進一步說明INotifyPropertyChanged與DependencyObjects的關聯。
-PhoneApplicationFrame與PhoneApplicationPage
一個PhoneApplicationFrame內,包括了PhoneApplicationPage控件與其他豐富的其他Microsoft.Phone.Controls下的其他控件,
然而,PhoneApplicationPage控件負責管理目前Frame中Content Area裡的所有任務與內容。
透過上圖是最好解釋整個Frame與Page的關係。
References:
‧Running a Windows Phone Application under the lock screen
‧wpf数据绑定,INotifyPropertyChanged vs DependencyProperty (—)
‧INotifyPropertyChanged and WPF
‧How to: Implement the INotifyPropertyChanged Interface
‧PhoneApplicationPage Control for Windows Phone
‧PhoneApplicationFrame Control for Windows Phone
‧《Programming WPF》翻译 第4章 2.数据绑定(2)
‧Base Controls for Windows Phone (Supported & Unsupported)
‧Class Library Reference for Windows Phone