引言:
當Windows Phone應用程序不在前臺運行的時候,抑或者應用程序在休眠狀態下或者設備鎖住的時候,計劃任務和後臺代理則可以運行在後臺,幫助應用程序來處理一些簡單的事務,今天開始,我將梳理自己所掌握的Windows Phone知識並結合內部資料,爭取更深的吃透Windows Phone平臺的運行機制.以此勉之!(PS: 不會按任何順序講述,需要讀者具備並瞭解XAML的數據綁定、MVVM設計模式以及其他相關的知識)。
後臺代理介紹
1、後臺代理的類型
- 週期性的任務,即:Periodic Task
- 資源密集性的任務,即: Resource Intensive Task.
2、當創建後臺代理時,你需要了解..
- 一個應用程序僅能運行一個後臺代理, 它可以是週期性的,也可以是資源密集性的,也可以是兩者共存。
- 任務計劃的運行,取決於你事先註冊 了哪種類型的代理任務。
- 在後臺代理中,不要把業務的關鍵邏輯寫進去,否則,你將會像調進泥潭一樣不能自拔,當初我們寫雲城客戶端時就碰到了類似的錯誤。
3、應該考慮哪些計劃任務的約束條件?
- 3.1、不支持的APIs
- 有些API在計劃任務中是不被支持的.
- 3.2、內存使用的限制
- 只有11MB內存可供利用
- 音頻類代理能夠使用到15MB內存。
- 3.3、每兩週可以改變計劃任務的需求設定
- 如果想讓某個計劃任務不再運行,可以設置該任務的過期時間屬性對象。
- 過期時間屬性的值至少要2周。
- 如果後臺代理任務被用於更新動態瓷貼,那麼過期時間自動順延2周時間。
- 如果需要在鎖屏界面中顯示通知,當你再次調用後臺代理時,過期時間同樣也會順延2周時間.
- 假設你的應用有照片上傳的功能,使用了資源密集型任務,這可能要求一直保持該任務運行,此時,你需要到 照片+相機 的設置頁中開啓.
- 3.4、如果應用程序有兩次不定期的崩潰,那麼,後臺代理任務的執行會變得混亂,不按原來的計劃執行。
以上是在使用後臺代理時應用注意的一些事項,各位在開發過程中,一定要注意這些,尤其是內存及時間的要求,接下來,我們來詳細看看週期性代理的實現原理及注意事項:
4、週期性代理
在我們正式開始編寫週期性代理任務之前,先來了解下週期代理的一些約束條件及注意事項,以便我們能夠更好的掌握、利用其特性。
- 4.1、計劃任務執行的間隔:通常是30分鐘執行一次。
- 4.2、計劃任務的連續性:每25秒運行。
- 4.3、如果開啓電源節約模式,週期性代理將不會運行。
- 4.4、在每臺設備中,只允許運行6個週期性代理。
5、代碼實戰
- 使用VS2013 RC創建簡單的後臺代理項目,如圖:
- 添加主要命名空間
using Microsoft.Phone.Shell;
- 在OnInvoke()方法中實現代理功能,本例子主要通過後臺代理,將消息通知到前臺,實現過程如下:
protected override void OnInvoke(ScheduledTask task) { //TODO: Add code to perform your task in background string ToastMessage = string.Empty; if (task is PeriodicTask) { ToastMessage = string.Format("週期性任務正在運行..."); } var toast = new ShellToast(); toast.Title = "後臺代理實戰!"; toast.Content = ToastMessage; toast.Show();
NotifyComplete(); #if DEBUG_AGENT //在調試模式下設定代理的運行時間間隔,如果不寫這段代理,那就只能等待.... ScheduledActionService.LaunchForTest(task.Name,TimeSpan.FromSeconds(60)); #endif }
- 實現MainPage.xaml頁面的UI佈局.
- 在項目中創建:ViewModel文件夾,創建名稱爲:PeriodicTaskConfigure.cs的週期代理任務配置。
#define DEBUG_AGENT using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Phone.Scheduler; namespace PhoneApp1.ViewModel { public class PeriodicTaskConfigure : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string name) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(name)); } } PeriodicTask periodicTask { get; set; } public string Name = "週期性代理"; private bool? _isEnabled; public bool? IsEnabled { get { return _isEnabled; } set { _isEnabled = value; OnPropertyChanged("IsEnabled"); } } private bool? _isScheduled; public bool? IsScheduled { get { return _isScheduled; } set { _isScheduled = value; OnPropertyChanged("IsScheduled"); } } private DateTime? _lastScheduledTime; public DateTime? LastScheduledTime { get { return _lastScheduledTime; } set { _lastScheduledTime = value; OnPropertyChanged("LastScheduledTime"); } } private DateTime? _expirationTime; public DateTime? ExpirationTime { get { return _expirationTime; } set { _expirationTime = value; OnPropertyChanged("ExpirationTime"); } } private string _LastExitReason;
public string LastExitReason { get { return _LastExitReason; } set { _LastExitReason = value; OnPropertyChanged("LastExitReason"); } } public void Page_Active() { periodicTask = ScheduledActionService.Find(Name) as PeriodicTask; if (periodicTask != null) { } } public void StartPeriodicAgent() { periodicTask = ScheduledActionService.Find(Name) as PeriodicTask; if (periodicTask != null) { RemoveAgent(); } periodicTask = new PeriodicTask(Name); periodicTask.Description = "這裏描述週期性代理的用途."; try { ScheduledActionService.Add(periodicTask); LoadPeriodicTaskData(); #if(DEBUG_AGENT) ScheduledActionService.LaunchForTest(Name, TimeSpan.FromSeconds(60)); #endif } catch (Exception e) { } } public void RemoveAgent() { try { ScheduledActionService.Remove(Name); EmptyPeriodicData(); } catch (Exception e) { } } private void LoadPeriodicTaskData() { this.IsEnabled = periodicTask.IsEnabled; this.IsScheduled = periodicTask.IsScheduled; this.LastScheduledTime = periodicTask.LastScheduledTime; this.LastExitReason = periodicTask.LastExitReason.ToString(); this.ExpirationTime = periodicTask.ExpirationTime; } private void EmptyPeriodicData() { this.IsEnabled = null; this.IsScheduled = null; this.LastScheduledTime = null; this.LastExitReason = null; ; this.ExpirationTime = null; } }
}
- 在App.xaml.cs中聲明 PeriodicTaskConfigure屬性,在App()構造函數中實現該類的一個對象。
private static PeriodicTaskConfigure _periodicTaskConfigure; public static PeriodicTaskConfigure periodicTaskConfigure { get { return _periodicTaskConfigure; } }
- 在MainPage.xaml.cs中,將DataContext設置爲PeriodicTaskConfigure的實現。
public MainPage() { InitializeComponent(); this.DataContext = App.periodicTaskConfigure; // Sample code to localize the ApplicationBar //BuildLocalizedApplicationBar(); }
- 經過如上設置,我們就可以在MainPage.xaml中去調用PeriodicTaskConfigure對象中的實現方法。
private void PeriodicCheckBox_Checked(object sender, RoutedEventArgs e) { App.periodicTaskConfigure.StartPeriodicAgent(); } private void PeriodicCheckBox_Unchecked(object sender, RoutedEventArgs e) { App.periodicTaskConfigure.RemoveAgent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { App.periodicTaskConfigure.Page_Active(); }
最終的實現效果是這個樣子地:
你的運行效果是這樣的麼?如果不是,彆着急,這裏有: Windows Phone 8 後臺代理 (P1:週期性代理) 源碼
如果有任何問題,請到 http://ask.metrofeng.com 提問,24小時在線解答。