HarmonyOS學習路之開發篇——Service Ability

Service Ability

Service Ability基本概念

基於Service模板的Ability(以下簡稱“Service”)主要用於後臺執行任務(如執行音樂播放、檔案下載等),但不提供使用者互動介面。Service可由其他應用或Ability啟動,即使使用者切換到其他應用,Service仍將在後臺繼續執行。

Service是單例項的。在一個裝置上,相同的Service只會存在一個例項。如果多個Ability共用這個例項,只有當與Service繫結的所有Ability都退出後,Service才能夠退出。由於Service是在主執行緒裡執行的,因此,如果在Service裡面的操作時間過長,開發者必須在Service裡建立新的執行緒來處理,防止造成主執行緒阻塞,應用程式無響應。

建立Service

介紹如何建立一個Service。

1、建立Ability的子類,實現Service相關的生命週期方法。Service也是一種Ability,Ability為Service提供了以下生命週期方法,透過重寫這些方法,來新增其他Ability請求與Service Ability互動時的處理方法。

onStart()

該方法在建立Service的時候呼叫,用於Service的初始化。在Service的整個生命週期只會呼叫一次,呼叫時傳入的Intent應為空。

onCommand()

在Service建立完成之後呼叫,該方法在客戶端每次啟動該Service時都會呼叫,使用者可以在該方法中做一些呼叫統計、初始化類的操作。

onConnect()

在Ability和Service連線時呼叫,該方法返回IRemoteObject物件,使用者可以在該回調函式中生成對應Service的IPC通訊通道,以便Ability與Service互動。Ability可以多次連線同一個Service,系統會快取該Service的IPC通訊物件,只有第一個客戶端連線Service時,系統才會呼叫Service的onConnect方法來生成IRemoteObject物件,而後系統會將同一個RemoteObject物件傳遞至其他連線同一個Service的所有客戶端,而無需再次呼叫onConnect方法。

onDisconnect()

在Ability與繫結的Service斷開連線時呼叫。

onStop()

在Service銷燬時呼叫。Service應透過實現此方法來清理任何資源,如關閉執行緒、註冊的偵聽器等。

建立Service的程式碼示例如下:

public class ServiceAbility extends Ability {@Overridepublic void onStart(Intent intent) {super。onStart(intent);}@Overridepublic void onCommand(Intent intent, boolean restart, int startId) {super。onCommand(intent, restart, startId);}@Overridepublic IRemoteObject onConnect(Intent intent) {return super。onConnect(intent);}@Overridepublic void onDisconnect(Intent intent) {super。onDisconnect(intent);}@Overridepublic void onStop() {super。onStop();}}

2、註冊Service。

Service也需要在應用配置檔案中進行註冊,註冊型別type需要設定為service。

{“module”: {“abilities”: [ { “name”: “。ServiceAbility”,“type”: “service”,“visible”: true。。。}]。。。}。。。}

啟動Service

介紹透過startAbility()啟動Service以及對應的停止方法。

啟動Service

Ability為開發者提供了startAbility()方法來啟動另外一個Ability。因為Service也是Ability的一種,開發者同樣可以透過將Intent傳遞給該方法來啟動Service。不僅支援啟動本地Service,還支援啟動遠端Service。

開發者可以透過構造包含DeviceId、BundleName與AbilityName的Operation物件來設定目標Service資訊。這三個引數的含義如下:

DeviceId:表示裝置ID。如果是本地裝置,則可以直接留空;如果是遠端裝置,可以透過ohos。distributedschedule。interwork。DeviceManager提供的getDeviceList獲取裝置列表,詳見《API參考》。

BundleName:表示包名稱。

AbilityName:表示待啟動的Ability名稱。

啟動本地裝置Service的程式碼示例如下:

Intent intent = new Intent();Operation operation = new Intent。OperationBuilder()。withDeviceId(“”)。withBundleName(“com。domainname。hiworld。himusic”)。withAbilityName(“com。domainname。hiworld。himusic。ServiceAbility”)。build();intent。setOperation(operation);startAbility(intent);

啟動遠端裝置Service的程式碼示例如下:

Intent intent = new Intent();Operation operation = new Intent。OperationBuilder()。withDeviceId(“deviceId”)。withBundleName(“com。domainname。hiworld。himusic”)。withAbilityName(“com。domainname。hiworld。himusic。ServiceAbility”)。withFlags(Intent。FLAG_ABILITYSLICE_MULTI_DEVICE) // 設定支援分散式排程系統多裝置啟動的標識。build();intent。setOperation(operation);startAbility(intent);

執行上述程式碼後,Ability將透過startAbility() 方法來啟動Service。

如果Service尚未執行,則系統會先呼叫onStart()來初始化Service,再回調Service的onCommand()方法來啟動Service。

如果Service正在執行,則系統會直接回調Service的onCommand()方法來啟動Service。

停止Service

Service一旦建立就會一直保持在後臺執行,除非必須回收記憶體資源,否則系統不會停止或銷燬Service。開發者可以在Service中透過terminateAbility()停止本Service或在其他Ability呼叫stopAbility()來停止Service。

停止Service同樣支援停止本地裝置Service和停止遠端裝置Service,使用方法與啟動Service一樣。一旦呼叫停止Service的方法,系統便會盡快銷燬Service。

連線Service

如果Service需要與Page Ability或其他應用的Service Ability進行互動,則須建立用於連線的Connection。Service支援其他Ability透過connectAbility()方法與其進行連線。

在使用connectAbility()處理回撥時,需要傳入目標Service的Intent與IAbilityConnection的例項。IAbilityConnection提供了兩個方法供開發者實現:onAbilityConnectDone()是用來處理連線Service成功的回撥,onAbilityDisconnectDone()是用來處理Service異常死亡的回撥。

建立連線Service回撥例項的程式碼示例如下:

// 建立連線Service回撥例項private IAbilityConnection connection = new IAbilityConnection() {// 連線到Service的回撥@Overridepublic void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int resultCode) {// Client側需要定義與Service側相同的IRemoteObject實現類。開發者獲取服務端傳過來IRemoteObject物件,並從中解析出服務端傳過來的資訊。}// Service異常死亡的回撥@Overridepublic void onAbilityDisconnectDone(ElementName elementName, int resultCode) {}};

連線Service的程式碼示例如下:

// 連線ServiceIntent intent = new Intent();Operation operation = new Intent。OperationBuilder()。withDeviceId(“deviceId”)。withBundleName(“com。domainname。hiworld。himusic”)。withAbilityName(“com。domainname。hiworld。himusic。ServiceAbility”)。build();intent。setOperation(operation);connectAbility(intent, connection);

同時,Service側也需要在onConnect()時返回IRemoteObject,從而定義與Service進行通訊的介面。onConnect()需要返回一個IRemoteObject物件,HarmonyOS提供了IRemoteObject的預設實現,使用者可以透過繼承LocalRemoteObject來建立自定義的實現類。Service側把自身的例項返回給呼叫側的程式碼示例如下:

// 建立自定義IRemoteObject實現類private class MyRemoteObject extends LocalRemoteObject {MyRemoteObject(){}}// 把IRemoteObject返回給客戶端@Overrideprotected IRemoteObject onConnect(Intent intent) {return new MyRemoteObject();}

Service Ability生命週期

與Page類似,Service也擁有生命週期,如圖1所示。根據呼叫方法的不同,其生命週期有以下兩種路徑:

啟動Service

該Service在其他Ability呼叫startAbility()時建立,然後保持執行。其他Ability透過呼叫stopAbility()來停止Service,Service停止後,系統會將其銷燬。

連線Service

該Service在其他Ability呼叫connectAbility()時建立,客戶端可透過呼叫disconnectAbility()斷開連線。多個客戶端可以繫結到相同Service,而且當所有繫結全部取消後,系統即會銷燬該Service。

圖1 Service生命週期

HarmonyOS學習路之開發篇——Service Ability

前臺Service

一般情況下,Service都是在後臺執行的,後臺Service的優先順序都是比較低的,當資源不足時,系統有可能回收正在執行的後臺Service。

在一些場景下(如播放音樂),使用者希望應用能夠一直保持執行,此時就需要使用前臺Service。前臺Service會始終保持正在執行的圖示在系統狀態列顯示。

使用前臺Service並不複雜,開發者只需在Service建立的方法裡,呼叫keepBackgroundRunning()將Service與通知繫結。呼叫keepBackgroundRunning()方法前需要在配置檔案中宣告ohos。permission。KEEP_BACKGROUND_RUNNING許可權,同時還需要在配置檔案中新增對應的backgroundModes引數。在onStop()方法中呼叫cancelBackgroundRunning()方法可停止前臺Service。

使用前臺Service的onStart()程式碼示例如下:

// 建立通知,其中1005為notificationIdNotificationRequest request = new NotificationRequest(1005);NotificationRequest。NotificationNormalContent content = new NotificationRequest。NotificationNormalContent();content。setTitle(“title”)。setText(“text”);NotificationRequest。NotificationContent notificationContent = new NotificationRequest。NotificationContent(content);request。setContent(notificationContent);// 繫結通知,1005為建立通知時傳入的notificationIdkeepBackgroundRunning(1005, request);

在配置檔案中,“module > abilities”欄位下對當前Service做如下配置:

{ “name”: “。ServiceAbility”,“type”: “service”,“visible”: true,“backgroundModes”: [“dataTransfer”, “location”]}