【WP8.1開發】認識后台任務


在手機上,使用后台,不像電腦上那么隨意,准確地講嘛,在移動平台上,后台任務都有嚴格的限制。至於說為什么會有這么多限制,我估計初衷很明顯——保證系統的性能不受某個或某幾個應用的負面影響;另外就是出於安全性考慮。

畢竟手機設備不同於電腦,一旦后台程序泛濫成災,是很難進行管理的,要防止這些不可預知的事件,只能從源頭上杜絕。因此,當初在RT應用上就是:允許后台任務,但你得按規矩做人

無規矩不成方圓,沒有限制就會亂象橫生,無法控制,現在某手機系統就深陷這一問題無法自撥,WP沒有必要重蹈這一覆轍。

好,前面廢話了那么多,就是要告訴大家,在開發的時候一定要想清楚,到底該不該使用后台任務,使用后台任務的話,一定要自己親測一下,是否會明顯消耗電量,是否會產生龐大的網絡流量。大家一定要養成一個好習慣——以做流氓程序為恥。說到這里,不得不鄙視一下國內的某些公司。

 

既然后台任務是有限制的,那么,官方是通過什么方式來限制的呢?

觸發器:后台任務必須通過觸發器來執行。這個觸發器,可以理解為類似生物的條件反射。清單文件給出的觸發類型有:后台音頻、計時器、系統維護等。記得前面我寫過博客,弄了一個在點亮屏幕時播放音樂,雖然這種做法不盡合理,但也作為一種參考吧。那個示例就是通過系統觸發器中的UserPresent類型觸發的,就是當用戶把手機屏幕點亮這一行為發生后就會執行后台任務。

比如,比較常用的還有計時器,這個應該會用得較多,比如每隔一段時間提取一批新聞列表等,如每30分鍾就執行一次。當然這計時器是有限制的,常規要求是至少15分鍾。不然的話,一些人品不端正的開發者弄個每分鍾觸發一次,那還得了,如果它是提取廣告的話,那不斷地彈廣告就會把用戶彈傻了。大家千萬別干這種事,你要干這種事,我只能說你太沒出息。

凡是實現了IBackgroundTrigger接口的都是觸發器,常以“Trigger”結尾,並不是所有觸發器都能用,有些是需要申請的,比如ChatMessageNotificationTrigger,這也是防止惡意程序的做法。

 

執行條件:這個主要由SystemCondition類表示。執行條件與觸發器不同,觸發器是表明在什么事實發生后執行后台任務,而執行條件是在什么情況下才能執行后台任務。你聽起來好像意思接近,實際上是不同的。比如,如果你的后台任務需要從網絡上獲取數據,而且觸發器為每25分鍾一次的計時器,於是在注冊后台任務時,你可以考慮增加一個執行條件:在有網絡連接的前提下執行。雖然計時器的時間到了,但正好這個時候,由於用戶的手機卡欠下4G流量費8622000元,被停機了,沒法上網,那么系統檢測到不存在有效的網絡連接,就不執行后台任務了(可以考慮用WiFi)。

 

如何使用后台任務

前面扯了一堆臊話,主要是讓朋友們對后台任務有個大致的了解,現在向大家介紹如何用后台。

代表后台任務的代碼通常應該寫在一個獨立的組件中,這樣做也比較科學的,有些朋友在開發程序時,喜歡把所有功能都塞到一個主程序里,許多人在開發桌面程序時就喜歡這樣,把所有功能都塞進一個exe中,連.dll都不舍得多用一個,我不喜歡這樣做的,一般我是一個功能模板用一個獨立的.dll,至於.exe用來放UI或者一些核心處理。

因此,第一步是向解決方案中添加一個Windows運行時組件,看清楚,是運行時組件,最后會生成.wimd文件,如果是類庫就會生成.dll文件。后台任務都應寫在Windows運行時組件中。這個應該會了吧,就是在“解決方案資源管理器”中新建項目,然后選Windows運行時組件,輸入項目名字就可以了,如果你不會這個,我只能告訴你:基礎不扎實,舉步艱難。

然后在新建的運行時組件中定義一個類,一定要是public的,不要問我為什么(請復習程序集的可訪問性),這個類要實現IBackgroundTask接口,表示它用於執行后台任務。

    public sealed class DemoTask : IBackgroundTask
    {
        public void Run ( IBackgroundTaskInstance taskInstance )
        {
            
        }
    }

重點是實現Run方法,當后台任務執行時,就是調用這個方法的,你的后台任務要做什么就寫在Run里面。
注意到有個IBackgroundTaskInstance類型的參數,是個接口,我們不用管它哪個類實現,這個在系統調用時會自動賦值,只關心它有哪些成員即可。

一定要明白GetDeferral方法的作用,它可以返回一個BackgroundTaskDeferral對象,這個對象的作用,說簡單一點就是用來拖延時間的,就是拖延后台任務的時間,當你覺得后台任務已經完成了,就調用用BackgroundTaskDeferral的Complete方法,告訴系統:任務做完了,系統收到報告后,就可以清理該任務了。

現在我們來實現一下這個任務。

        public void Run ( IBackgroundTaskInstance taskInstance )
        {
            var def = taskInstance.GetDeferral();
            // 獲取XML模板
            XmlDocument docx = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
            // 修改XML
            var eles = docx.GetElementsByTagName("text");
            if (eles.Count < 2)
            {
                def.Complete();
                return;
            }
            XmlElement text01 = (XmlElement)eles[0];
            text01.AppendChild(docx.CreateTextNode("示例"));
            XmlElement text02 = (XmlElement)eles[1];
            text02.AppendChild(docx.CreateTextNode("后台任務執行了。"));

            // 產生Toast通知
            ToastNotification notification = new ToastNotification(docx);
            // 顯示通知
            ToastNotificationManager.CreateToastNotifier().Show(notification);

            // 報告任務完成
            def.Complete();
        }


這個任務,不復雜,就是向用戶發一條Toast通知。

 

好,后台任務已經寫好了,現在要在主項目中對它進行引用,一定不要忘了,只有引用了上面寫的Windows運行時組件才能訪問它,這和以前.net項目一樣。

 

這個后台任務,我打算讓它每40分鍾執行一次,所以觸發器應選用TimeTrigger。下面先簡單設計一下UI。

    <StackPanel>
        <Button Content="注冊后台任務" Click="開始注冊"/>
        <Button Content="取消后台任務" Click="取消注冊"/>
        <TextBlock x:Name="tb" FontSize="20" TextWrapping="Wrap"/>
    </StackPanel>

界面簡單,你看得懂的,其實事件處理的方法名是可以用中文的,在VS里面,類型名、命名空間名、成員名、參數名都可以用中文的,如果你不喜歡英文名字,可以用中文。

通常,注冊后台任務需要准備以下證件:

1、個人身份證,即后台任務的名字,這個名字必須唯一,不能與現有的任務重復。

2、戶口本。即入口點,指的是我們前面在Windows運行時組件中定義的那個類的類名,就是那個實現IBackgroundTask接口以及Run方法的類。

為了在輸入代碼時不容易輸入,最好先將這些內容聲明為常量。

        /// <summary>
        /// 任務的唯一名稱
        /// </summary>
        const string TASK_NAME = "haha_task";
        /// <summary>
        /// 入口點
        /// </summary>
        const string ENTRY_POINT = "BackTest.DemoTask";

注意,入口點的名字是要包含命名空間名字的。

 

好,前期手續基本辦完,現在可以正式注冊了。下面代碼分別用於注冊和取消注冊后台任務。

        private async void 開始注冊 ( object sender, RoutedEventArgs e )
        {
            var res = await BackgroundExecutionManager.RequestAccessAsync();
            if (res != BackgroundAccessStatus.AllowedMayUseActiveRealTimeConnectivity)
                return;

            // 注冊
            BackgroundTaskBuilder bd = new BackgroundTaskBuilder();
            bd.Name = TASK_NAME; //任務名
            bd.TaskEntryPoint = ENTRY_POINT; //入口點
            // 設置觸發器為計時器
            bd.SetTrigger(new TimeTrigger(40, false));
            try
            {
                BackgroundTaskRegistration reg = bd.Register();
                // 注冊成功,顯示結果
                tb.Text = string.Format("任務名:{0}\n任務ID:{1}", reg.Name, reg.TaskId);
            }
            catch (Exception ex)
            {
                tb.Text = ex.Message;
            }
        }

        private void 取消注冊 ( object sender, RoutedEventArgs e )
        {
            // 先查找一下是否已經注冊了任務
            var task = BackgroundTaskRegistration.AllTasks.Values.FirstOrDefault(t => t.Name == TASK_NAME);
            if (task != null)
            {
                // 取消
                task.Unregister(true);
            }
        }


1、在注冊之前一定要調用BackgroundExecutionManager.RequestAccessAsync方法,是然不會彈出任何提示,但不要忘了,不調用是不能注冊的。

2、BackgroundTaskBuilder類,顧名思義,就是用來注冊后台任務的。

3、TimeTrigger觸發器的構造函數的第二個參數如果為true,那后台任務只運行一次,這里我希望它每40分鍾運行一次,所以為false。

 

現在,離成果不遠了,但是還有一步很關鍵,那就是配置清單文件。

打開Package.appxmanifest文件,切換到“聲明”選項頁,在可用的聲明列表中選“后台任務”,然后點擊添加按鈕。

在右邊的頁面中,按實際情況勾選,我這個例子是計時的,所以選計時器,然后在下面再填寫一下入口點,這個入口點和注冊后台任務時用的入口點是一樣的,可以直接從剛才的代碼中復制過來。

因為本例要用到Toast通知,所以要讓應用支持Toast。切換到“應用程序”選項卡,在下面有關通知設置的地方,將支持Toast通知設置為“是”。

最后,保存並關閉清單文件。

 

如何調試后台任務

像我這個例子,要等40分鍾才執行的,難道我在干等不成? 非也,我們不用在那里苦等40分鍾,VS會幫助我們進行調試的。

首先,運行應用程序,然后點頁面上的注冊按鈕,確保后台任務已經成功注冊。

 

然后回到VS,在“調試位置”工具上,點擊“生命周期事件”按鈕右邊的下拉箭頭,從下拉菜單中你會看到有后台任務的名字。如下圖。

如果看不到,你可以稍等一下,如果一直不出現,你可以重復上面的步驟。只要后台任務注冊成功的,肯定會顯示的(后台音頻和推送通知除外)。

所以,現在你調試后台任務就很方便,直從“調試位置”工具欄的下拉菜單中選中后台任務,后台任務就會執行了。

 

OK,相信通過這篇破文,初學者能夠初步認識后台任務。

示例源碼:http://files.cnblogs.com/tcjiaan/SampleAppBackTask.zip

 


免責聲明!

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



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