HarmonyOS學(xué)習(xí)路之開(kāi)發(fā)篇—Service Ability
1
Service Ability基本概念
基于Service模板的Ability(以下簡(jiǎn)稱(chēng)“Service”)主要用于后臺(tái)運(yùn)行任務(wù)(如執(zhí)行音樂(lè)播放、文件下載等),但不提供用戶(hù)交互界面。Service可由其他應(yīng)用或Ability啟動(dòng),即使用戶(hù)切換到其他應(yīng)用,Service仍將在后臺(tái)繼續(xù)運(yùn)行。
Service是單實(shí)例的。在一個(gè)設(shè)備上,相同的Service只會(huì)存在一個(gè)實(shí)例。如果多個(gè)Ability共用這個(gè)實(shí)例,只有當(dāng)與Service綁定的所有Ability都退出后,Service才能夠退出。
由于Service是在主線(xiàn)程里執(zhí)行的,因此,如果在Service里面的操作時(shí)間過(guò)長(zhǎng),開(kāi)發(fā)者必須在Service里創(chuàng)建新的線(xiàn)程來(lái)處理,防止造成主線(xiàn)程阻塞,應(yīng)用程序無(wú)響應(yīng)。
創(chuàng)建Service
介紹如何創(chuàng)建一個(gè)Service。
1、創(chuàng)建Ability的子類(lèi),實(shí)現(xiàn)Service相關(guān)的生命周期方法。Service也是一種Ability,Ability為Service提供了以下生命周期方法,通過(guò)重寫(xiě)這些方法,來(lái)添加其他Ability請(qǐng)求與Service Ability交互時(shí)的處理方法。
onStart() 該方法在創(chuàng)建Service的時(shí)候調(diào)用,用于Service的初始化。在Service的整個(gè)生命周期只會(huì)調(diào)用一次,調(diào)用時(shí)傳入的Intent應(yīng)為空。 onCommand() 在Service創(chuàng)建完成之后調(diào)用,該方法在客戶(hù)端每次啟動(dòng)該Service時(shí)都會(huì)調(diào)用,用戶(hù)可以在該方法中做一些調(diào)用統(tǒng)計(jì)、初始化類(lèi)的操作。 onConnect() 在Ability和Service連接時(shí)調(diào)用,該方法返回IRemoteObject對(duì)象,用戶(hù)可以在該回調(diào)函數(shù)中生成對(duì)應(yīng)Service的IPC通信通道,以便Ability與Service交互。Ability可以多次連接同一個(gè)Service,系統(tǒng)會(huì)緩存該Service的IPC通信對(duì)象,只有第一個(gè)客戶(hù)端連接Service時(shí),系統(tǒng)才會(huì)調(diào)用Service的onConnect方法來(lái)生成IRemoteObject對(duì)象,而后系統(tǒng)會(huì)將同一個(gè)RemoteObject對(duì)象傳遞至其他連接同一個(gè)Service的所有客戶(hù)端,而無(wú)需再次調(diào)用onConnect方法。 onDisconnect() 在Ability與綁定的Service斷開(kāi)連接時(shí)調(diào)用。 onStop() 在Service銷(xiāo)毀時(shí)調(diào)用。Service應(yīng)通過(guò)實(shí)現(xiàn)此方法來(lái)清理任何資源,如關(guān)閉線(xiàn)程、注冊(cè)的偵聽(tīng)器等。創(chuàng)建Service的代碼示例如下:
public class ServiceAbility extends Ability {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
}
@Override
public void onCommand(Intent intent, boolean restart, int startId) {
super.onCommand(intent, restart, startId);
}
@Override
public IRemoteObject onConnect(Intent intent) {
return super.onConnect(intent);
}
@Override
public void onDisconnect(Intent intent) {
super.onDisconnect(intent);
}
@Override
public void onStop() {
super.onStop();
}
}
2、注冊(cè)Service。Service也需要在應(yīng)用配置文件中進(jìn)行注冊(cè),注冊(cè)類(lèi)型type需要設(shè)置為service。
{
"module": {
"abilities": [
{
"name": ".ServiceAbility",
"type": "service",
"visible": true
...
}
]
...
}
...
}
啟動(dòng)Service
介紹通過(guò)startAbility()啟動(dòng)Service以及對(duì)應(yīng)的停止方法。
啟動(dòng)Service Ability為開(kāi)發(fā)者提供了startAbility()方法來(lái)啟動(dòng)另外一個(gè)Ability。因?yàn)镾ervice也是Ability的一種,開(kāi)發(fā)者同樣可以通過(guò)將Intent傳遞給該方法來(lái)啟動(dòng)Service。不僅支持啟動(dòng)本地Service,還支持啟動(dòng)遠(yuǎn)程Service。開(kāi)發(fā)者可以通過(guò)構(gòu)造包含DeviceId、BundleName與AbilityName的Operation對(duì)象來(lái)設(shè)置目標(biāo)Service信息。這三個(gè)參數(shù)的含義如下: DeviceId:表示設(shè)備ID。如果是本地設(shè)備,則可以直接留空;如果是遠(yuǎn)程設(shè)備,可以通過(guò)ohos.distributedschedule.interwork.DeviceManager提供的getDeviceList獲取設(shè)備列表,詳見(jiàn)《API參考》。 BundleName:表示包名稱(chēng)。 AbilityName:表示待啟動(dòng)的Ability名稱(chēng)。
啟動(dòng)本地設(shè)備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);
啟動(dòng)遠(yuǎn)程設(shè)備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) // 設(shè)置支持分布式調(diào)度系統(tǒng)多設(shè)備啟動(dòng)的標(biāo)識(shí)
.build();
intent.setOperation(operation);
startAbility(intent);
執(zhí)行上述代碼后,Ability將通過(guò)startAbility() 方法來(lái)啟動(dòng)Service。
如果Service尚未運(yùn)行,則系統(tǒng)會(huì)先調(diào)用onStart()來(lái)初始化Service,再回調(diào)Service的onCommand()方法來(lái)啟動(dòng)Service。
如果Service正在運(yùn)行,則系統(tǒng)會(huì)直接回調(diào)Service的onCommand()方法來(lái)啟動(dòng)Service。
停止Service Service一旦創(chuàng)建就會(huì)一直保持在后臺(tái)運(yùn)行,除非必須回收內(nèi)存資源,否則系統(tǒng)不會(huì)停止或銷(xiāo)毀Service。開(kāi)發(fā)者可以在Service中通過(guò)terminateAbility()停止本Service或在其他Ability調(diào)用stopAbility()來(lái)停止Service。停止Service同樣支持停止本地設(shè)備Service和停止遠(yuǎn)程設(shè)備Service,使用方法與啟動(dòng)Service一樣。一旦調(diào)用停止Service的方法,系統(tǒng)便會(huì)盡快銷(xiāo)毀Service。
連接Service
如果Service需要與Page Ability或其他應(yīng)用的Service Ability進(jìn)行交互,則須創(chuàng)建用于連接的Connection。Service支持其他Ability通過(guò)connectAbility()方法與其進(jìn)行連接。
在使用connectAbility()處理回調(diào)時(shí),需要傳入目標(biāo)Service的Intent與IAbilityConnection的實(shí)例。IAbilityConnection提供了兩個(gè)方法供開(kāi)發(fā)者實(shí)現(xiàn):onAbilityConnectDone()是用來(lái)處理連接Service成功的回調(diào),onAbilityDisconnectDone()是用來(lái)處理Service異常死亡的回調(diào)。
創(chuàng)建連接Service回調(diào)實(shí)例的代碼示例如下:
// 創(chuàng)建連接Service回調(diào)實(shí)例
private IAbilityConnection connection = new IAbilityConnection() {
// 連接到Service的回調(diào)
@Override
public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int resultCode) {
// Client側(cè)需要定義與Service側(cè)相同的IRemoteObject實(shí)現(xiàn)類(lèi)。開(kāi)發(fā)者獲取服務(wù)端傳過(guò)來(lái)IRemoteObject對(duì)象,并從中解析出服務(wù)端傳過(guò)來(lái)的信息。
}
// Service異常死亡的回調(diào)
@Override
public void onAbilityDisconnectDone(ElementName elementName, int resultCode) {
}
};
連接Service的代碼示例如下:
// 連接Service
Intent 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);
同時(shí),Service側(cè)也需要在onConnect()時(shí)返回IRemoteObject,從而定義與Service進(jìn)行通信的接口。onConnect()需要返回一個(gè)IRemoteObject對(duì)象,HarmonyOS提供了IRemoteObject的默認(rèn)實(shí)現(xiàn),用戶(hù)可以通過(guò)繼承LocalRemoteObject來(lái)創(chuàng)建自定義的實(shí)現(xiàn)類(lèi)。Service則把自身的實(shí)例返回給調(diào)用側(cè)的代碼示例如下:
// 創(chuàng)建自定義IRemoteObject實(shí)現(xiàn)類(lèi)
private class MyRemoteObject extends LocalRemoteObject {
MyRemoteObject(){
}
}
// 把IRemoteObject返回給客戶(hù)端
@Override
protected IRemoteObject onConnect(Intent intent) {
return new MyRemoteObject();
}
2
Service Ability生命周期
與Page類(lèi)似,Service也擁有生命周期,如圖1所示。根據(jù)調(diào)用方法的不同,其生命周期有以下兩種路徑:
啟動(dòng)Service 該Service在其他Ability調(diào)用startAbility()時(shí)創(chuàng)建,然后保持運(yùn)行。其他Ability通過(guò)調(diào)用stopAbility()來(lái)停止Service,Service停止后,系統(tǒng)會(huì)將其銷(xiāo)毀。 連接Service 該Service在其他Ability調(diào)用connectAbility()時(shí)創(chuàng)建,客戶(hù)端可通過(guò)調(diào)用disconnectAbility()斷開(kāi)連接。多個(gè)客戶(hù)端可以綁定到相同Service,而且當(dāng)所有綁定全部取消后,系統(tǒng)即會(huì)銷(xiāo)毀該Service。

圖1 Service生命周期
3
前臺(tái)Service
一般情況下,Service都是在后臺(tái)運(yùn)行的,后臺(tái)Service的優(yōu)先級(jí)都是比較低的,當(dāng)資源不足時(shí),系統(tǒng)有可能回收正在運(yùn)行的后臺(tái)Service。
在一些場(chǎng)景下(如播放音樂(lè)),用戶(hù)希望應(yīng)用能夠一直保持運(yùn)行,此時(shí)就需要使用前臺(tái)Service。前臺(tái)Service會(huì)始終保持正在運(yùn)行的圖標(biāo)在系統(tǒng)狀態(tài)欄顯示。
使用前臺(tái)Service并不復(fù)雜,開(kāi)發(fā)者只需在Service創(chuàng)建的方法里,調(diào)用keepBackgroundRunning()將Service與通知綁定。調(diào)用keepBackgroundRunning()方法前需要在配置文件中聲明ohos.permission.KEEP_BACKGROUND_RUNNING權(quán)限,同時(shí)還需要在配置文件中添加對(duì)應(yīng)的backgroundModes參數(shù)。在onStop()方法中調(diào)用cancelBackgroundRunning()方法可停止前臺(tái)Service。
使用前臺(tái)Service的onStart()代碼示例如下:
// 創(chuàng)建通知,其中1005為notificationId
NotificationRequest 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為創(chuàng)建通知時(shí)傳入的notificationId
keepBackgroundRunning(1005, request);
在配置文件中,“module > abilities”字段下對(duì)當(dāng)前Service做如下配置:
{
"name": ".ServiceAbility",
"type": "service",
"visible": true,
"backgroundModes": ["dataTransfer", "location"]
}
往期推薦

