Windows Phone Background Agent雜談


Windows Phone從Mango開始開放了Background Agent,使得我們可以實現后台運行的任務。出於興趣,我在第一時間使用這套API開發了一個應用——Human Calendar。隨着時間的推移、功能的增加,Human Calendar越來越依賴於Background Agent,也逐漸遇到了更多讓人頭疼的問題。經過許多摸索和撞牆后,絕大多數問題都解決了,Human Calendar目前運行良好。所以我就用這篇文章來記錄一下開發Background Agent過程中的一些事情,但我不會完整地介紹一個Background Agent的開發過程,你大可將本文看成一篇“吐槽”文。

 

限制

在開發Background Agent之前,必須要考慮到它的限制,因為這些限制極其嚴格,對於定期代理(PeriodicTask)來說,限制了:

  1. 有一些API不能使用,並不是說你不調用就可以了,只要你在同一個程序集里使用了這些API,就不會通過驗證;
  2. 內存占用不能超過6MB,否則立即終止;
  3. 生效時間最長只有14天,過期后就需要重新計划。Human Calendar和一些天氣應用都屬於那種只要有Tile就可以一輩子不去打開的應用,但是由於這個限制,我還得想辦法提醒用戶:“親,記住兩周內重新打開應用一次哦,不然Tile就沒法更新了哦”;
  4. 連續兩次崩潰之后會被禁用,做好准備捕捉一切異常吧;
  5. 每30分鍾運行一次,每次最多執行25秒,超時后立即終止,所以如果在后台任務里下載文件的話,要特別注意文件的大小;
  6. 節電模式會阻止執行;
  7. 手機中的后台任務數量是有上限的,最少為6個,當手機中已啟用的后台任務達到上限后,就無法再啟用新的后台任務了,這時候你還得提醒用戶:“親,到這里的這里的這里看看后台任務是不是超過6個了,是的話,挑一個禁用了,然后回來再試試”……

 

資源密集型代理

除了定期代理之外,Windows Phone還支持另外一種后台任務——資源密集型代理(ResourceIntensiveTask),不過我們通常都不會用到它,因為它簡直就是個杯具,它的限制不僅多,而且都很變態,除了擁有定期代理的前4挑限制之外,它還限制了:

  • 電池電量不得低於90%,而且需要連接外部電源;
  • 需要非手機網絡連接,連着WIFI或PC吧,親;
  • 屏幕必須鎖定,也不能接打電話,否則不執行;
  • 最多執行10分鍾,超時立即終止;

想像一下,假如有個應用使用了資源密集型代理,它該怎么向用戶解釋?

“親,想要使用我們的XXX功能,您得先充滿電,再連着WIFI,鎖住屏幕,安靜的等待10分鍾,期間千萬別拔開電源線,也別解鎖屏幕和接打電話哦。”

用戶“哦”了一聲,然后隨手卸載了應用。

 

調試

可以使用ScheduledActionService.LaunchForTest方法來隨時隨地執行后台任務,籍此來進行調試。此方法在Debug和Release模式下均可執行,但在用戶下載的應用中是無效的,所以不要妄想用它來突破Background Agent的時間限制。

雖然在Visual Studio中進行調試非常方便,但不可過於相信調試器。簡單來說,附加了調試器的Background Agent就像被提升了權限一樣,可以執行一些正常狀態下不能執行的任務,譬如可以調用BitmapImage.SetSource方法,而在沒有附加調試器的后台任務中調用這個方法是會拋出異常的(可以使用WriteableBitmapImage來代替)。

所以很有必要在不附加調試器的情況下檢查Background Agent的運行情況。

這時就可以利用ScheduledActionService.LaunchForTest來將Background Agent安排在一段時間后執行,然后退出應用,關閉調試器(早期的SDK會在退出應用時自動關閉調試器),觀察效果。

假如發現后台任務出現了問題,該怎么定位問題?有兩種特別原始的方法:第一種是在執行后台任務的的同時寫日志;第二種是Toast通知(我想起了史前程序員使用alert調試JavaScript的故事)。

由於第4條限制,所以很有必要勤快的使用try-catch,但比較不幸的是並不是所有異常都會被捕捉到,所有因為超出限制而導致的終止行為都無法捕捉到,而且在某些情況下,一些看起來很正常的異常也會跳過catch直接殺死后台任務。

所以日志和Toast通知就相當重要,你可以根據最后一條消息的位置來推斷代碼執行到了何處,從而找到出問題的代碼,然后再研究為什么會出問題。

這里還有一個插曲,在早期的SDK中有這樣一個問題,如果附加了調試器,Background Agent就永遠不會執行,於是我眼睜睜的盯着模擬器浪費了一個大好的下午,人生苦短啊,還好這個問題現在已經修復了。

 

檢測時間和內存占用

Background Agent在時間上有許多限制,對於第3條限制,我們別無他法,因為添加后台任務的API屬於受限API,不能在Background Agent中調用,所以只能提醒用戶每14天內至少要打開一次應用,然后在每次打開應用的時候自動重新啟用后台任務(這樣它就又能活14天了)。

對於第2條和第5條限制,我們只能想辦法控制執行時間,盡量把任務細化成小任務,讓每個小任務都有自己的唯一標識和完成狀態,並且可以被持久化,然后用遞歸或者遍歷的方式依次執行這些小任務,每次執行時都要檢查當前已執行的時間和已占用的內存,如果發現接近某個臨界值,就NotifyComplete,然后期待半小時后繼續。

臨界值可以根據第2條和第5條限制以及小任務們的平均執行時間和內存占用來設定,留出一定的空檔以防不測。

此外,如果應用中使用了本地數據庫,最好不要在后台任務中初始化甚至使用,它會帶來極大的內存消耗。就拿Human Calendar來說,用IsolatedStorageSettings取代了本地數據庫之后,內存竟然節省了一半(而且這個數據庫還無比簡單,只有一張表、五個列和七八條數據)。

 

資源

應用:Human Calendar,我承認這個應用很宅,不過還是歡迎捧場……

MSDN:《Windows Phone的后台代理》,寫本文時候發現這篇文章在年初還更新了一次,增加了不少內容,MSDN上的Windows Phone文章更新速度還是蠻快的。

最后吐槽一次,MSDN上把Reference翻譯成“書評”這種事情是哪個實習生干的?


免責聲明!

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



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