共用方式為


建立 Android 服務

本指南討論 Xamarin.Android 服務,這是允許在沒有作用中使用者介面的情況下完成工作的 Android 元件。 服務通常用於背景中執行的工作,例如耗時的計算、下載檔案、播放音樂等等。 它說明服務適合的不同案例,並示範如何實作它們來執行長時間執行的背景工作,以及提供遠端過程調用的介面。

Android 服務概觀

行動應用程式不像傳統型應用程式。 桌面電腦擁有大量資源,例如螢幕房地產、記憶體、儲存空間,以及連接的電源供應器,行動裝置則不會。 這些限制會強制行動應用程式以不同的方式運作。 例如,行動裝置上的小型畫面通常表示一次只會顯示一個應用程式(亦即活動)。 其他活動會移至背景,並推送至無法執行任何工作的暫停狀態。 不過,僅僅因為Android應用程式位於背景,並不表示應用程式無法繼續運作。

Android 應用程式至少由下列四個主要元件之一組成:活動、廣播接收者、內容提供者和服務。 活動是許多絕佳 Android 應用程式的基石,因為它們提供可讓使用者與應用程式互動的 UI。 不過,當涉及到執行並行或背景工作時,活動不一定是最佳選擇。

Android 中背景工作的主要機制是 服務。 Android 服務是一種元件,其設計目的是在沒有使用者介面的情況下執行某些工作。 服務可能會下載檔案、播放音樂,或將篩選條件套用至影像。 服務也可用於Android應用程式之間的進程間通訊(IPC)。 例如,一個 Android 應用程式可能會使用來自另一個應用程式的音樂播放程式服務,或應用程式可能會透過服務向其他應用程式公開資料(例如人員的連絡資訊)。

服務及其執行背景工作的能力,對於提供流暢且流暢的使用者介面至關重要。 所有 Android 應用程式都有活動 執行所在的主線程 (也稱為 UI 線程)。 若要讓裝置保持回應,Android 必須能夠以每秒 60 個畫面格的速率更新使用者介面。 如果Android應用程式在主線程上執行太多工作,則Android會卸除畫面格,這反過來又會導致UI顯示為混蛋(有時也稱為 簡訊)。 這表示在UI線程上執行的任何工作都應該在兩個畫面之間的時間範圍中完成,大約16毫秒(每60個畫面格1秒)。

為了解決這個問題,開發人員可能會使用活動中的線程來執行會封鎖UI的某些工作。 不過,這可能會造成問題。 Android 可能會終結並重新建立活動的多個實例。 不過,Android 不會自動終結線程,這可能會導致記憶體流失。 其中的主要範例是當裝置旋轉– Android 會嘗試終結活動的實例,然後重新建立新的實例:

When device rotates, instance 1 is destroyed and instance 2 is created

這是潛在的記憶體流失 – 活動第一個實例所建立的線程仍會執行中。 如果線程有活動第一個實例的參考,這會防止Android垃圾收集物件。 不過,仍會建立活動的第二個實例(接著可能會建立新的線程)。 連續旋轉裝置數次可能會耗盡所有 RAM,並強制 Android 終止整個應用程式以回收記憶體。

根據經驗法則,如果要執行的工作應該超過活動,則應該建立服務來執行該工作。 不過,如果工作僅適用於活動的內容,則建立線程來執行工作可能更合適。 例如,為剛新增至相片庫應用程式的相片建立縮圖,應該會發生在服務中。 不過,線程可能更適合播放一些只有在活動處於前景時才應該聽到的音樂。

背景工作可以細分成兩個廣泛的分類:

  1. 長時間執行的工作 – 這是持續到明確停止的工作。 長時間執行工作的範例是串流音樂或必須監視從感測器收集的數據的應用程式。 即使應用程式沒有可見的使用者介面,這些工作仍必須執行。
  2. 定期工作 – (有時稱為 作業)定期工作是持續時間相對較短(幾秒)且會依排程執行的工作(也就是一週一天執行一次,或在未來 60 秒內只執行一次)。 其中一個範例是從因特網下載檔案,或產生影像的縮圖。

Android 服務有四種不同類型的:

  • 系結服務 – 系 結服務 是系結至它的一些其他元件(通常是活動)的服務。 系結服務提供介面,可讓系結元件和服務彼此互動。 一旦沒有任何客戶端系結至服務,Android 就會關閉服務。

  • IntentServiceIntentService– 是 類別的特殊子類別,Service可簡化服務建立和使用方式。 IntentService意在處理個別的自發呼叫。 不同於可以同時處理多個呼叫的服務,更 IntentService 像是 工作佇列處理器 – 工作會排入佇列,並在 IntentService 單一背景工作線程上一次處理每個作業。 一般而言,IntentService 不會系結至活動或片段。

  • 啟動服務已啟動的服務 是其他 Android 元件已啟動的服務(例如活動),並持續在背景中執行,直到明確告知服務停止為止。 不同於系結服務,已啟動的服務沒有直接系結至它的任何用戶端。 基於這個理由,請務必設計已啟動的服務,以便視需要正常重新啟動。

  • 混合式服務 – 混合式服務是具有已啟動服務和系結服務特性的服務。 當元件系結至混合式服務,或可能由某些事件啟動時,即可啟動混合式服務。 用戶端元件不一定會系結至混合式服務。 混合式服務會持續執行,直到明確告知停止,或直到沒有其他客戶端系結為止。

要使用的服務類型非常相依於應用程式需求。 根據經驗法則, IntentService 或系結服務就足以處理 Android 應用程式必須執行的大部分工作,因此應該將喜好設定提供給這兩種服務類型的其中一種。 IntentService是「單次」工作的絕佳選擇,例如下載檔案,而系結服務則適合在經常與活動/片段互動時使用。

雖然大部分服務在背景中執行,但有一個 稱為前景服務的特殊子類別。 這是一項服務,其優先順序較高(相較於一般服務),為用戶執行一些工作(例如播放音樂)。

您也可以在同一部裝置上自行執行服務,這有時稱為 遠端服務跨進程服務。 這確實需要建立更多工作,但當應用程式需要與其他應用程式共用功能時,而且在某些情況下,可以改善應用程式的用戶體驗。

Android 8.0 中的背景執行限制

從 Android 8.0 (API 層級 26) 開始,Android 應用程式就不再能夠在背景自由執行。 在前景時,應用程式可以啟動並執行服務,而不受限制。 當應用程式進入背景時,Android 會授與應用程式一定時間來啟動和使用服務。 一旦經過該時間,應用程式就無法再啟動任何服務,且任何已啟動的服務都將終止。 此時,應用程式無法執行任何工作。 如果符合下列其中一個條件,Android 會將應用程式視為在前景:

  • 有可見的活動(已啟動或暫停)。
  • 應用程式已啟動前景服務。
  • 另一個應用程式位於前景,並且使用來自背景否則為應用程式的元件。 其中一個範例是,如果應用程式 A 位於前景,系結至應用程式 B 所提供的服務。應用程式 B 接著也會在前景考慮,而不是由 Android 終止以在背景中。

在某些情況下,即使應用程式位於背景,Android 還是會喚醒應用程式並放寬這些限制幾分鐘,讓應用程式執行一些工作:

  • 應用程式會收到高優先順序的 Firebase 雲端訊息。
  • 應用程式會收到廣播。
  • 應用程式會接收並執行 PendingIntent ,以回應通知。

現有的 Xamarin.Android 應用程式可能必須變更其執行背景工作的方式,以避免 Android 8.0 上可能發生的任何問題。 以下是 Android 服務的一些實用替代方案:

  • 使用 Android 作業排程器或 Firebase 作業發送器 來排程背景執行的工作 – 這兩個連結庫提供一個架構,讓應用程式將背景工作隔離到 作業,這是一個離散的工作單位。 然後,應用程式可以使用作業系統排程作業,以及作業執行時機的一些準則。
  • 在前景 啟動服務 – 前景服務適用於應用程式必須在背景中執行某些工作,且使用者可能需要定期與該工作互動。 前景服務會顯示持續性通知,讓使用者知道應用程式正在執行背景工作,也提供監視或與工作互動的方式。 其中一個範例是播客應用程式,將播客播放給使用者,或下載播客情節,以便稍後可以享受。
  • 使用高優先順序的 Firebase 雲端訊息 (FCM) – 當 Android 收到應用程式的高優先順序 FCM 時,它會允許該應用程式在背景執行服務一段短時間內。 這是讓背景服務在背景輪詢應用程式的絕佳替代方案。
  • 當應用程式進入前景 時延遲工作 – 如果上述任何解決方案都可行,則當應用程式進入前景時,應用程式必須開發自己的方法來暫停和繼續工作。