Service Ability
Service Ability基本概念
基于Service模板的Ability(如下简称“Service”)主要用于后台运行任务(如执行音乐播放、文件下载等),但不提供用户交互界面。Service可由其余应用或Ability启动,即便用户切换到其余应用,Service仍将在后台继续运行。java
Service是单实例的。在一个设备上,相同的Service只会存在一个实例。若是多个Ability共用这个实例,只有当与Service绑定的全部Ability都退出后,Service才可以退出。因为Service是在主线程里执行的,所以,若是在Service里面的操做时间过长,开发者必须在Service里建立新的线程来处理,防止形成主线程阻塞,应用程序无响应。json
建立Service
介绍如何建立一个Service。 一、建立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 { @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(); } }
二、注册Service。 Service也须要在应用配置文件中进行注册,注册类型type须要设置为service。dom
{ "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的代码示例以下:ide
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。ui
-
若是Service还没有运行,则系统会先调用onStart()来初始化Service,再回调Service的onCommand()方法来启动Service。线程
-
若是Service正在运行,则系统会直接回调Service的onCommand()方法来启动Service。rest
-
中止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的回调 @Override public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int resultCode) { // Client侧须要定义与Service侧相同的IRemoteObject实现类。开发者获取服务端传过来IRemoteObject对象,并从中解析出服务端传过来的信息。 } // Service异常死亡的回调 @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);
同时,Service侧也须要在onConnect()时返回IRemoteObject,从而定义与Service进行通讯的接口。onConnect()须要返回一个IRemoteObject对象,HarmonyOS提供了IRemoteObject的默认实现,用户能够经过继承LocalRemoteObject来建立自定义的实现类。Service侧把自身的实例返回给调用侧的代码示例以下:
// 建立自定义IRemoteObject实现类 private class MyRemoteObject extends LocalRemoteObject { MyRemoteObject(){ } } // 把IRemoteObject返回给客户端 @Override protected 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生命周期
前台Service
通常状况下,Service都是在后台运行的,后台Service的优先级都是比较低的,当资源不足时,系统有可能回收正在运行的后台Service。
在一些场景下(如播放音乐),用户但愿应用可以一直保持运行,此时就须要使用前台Service。前台Service会始终保持正在运行的图标在系统状态栏显示。
使用前台Service并不复杂,开发者只需在Service建立的方法里,调用keepBackgroundRunning()将Service与通知绑定。调用keepBackgroundRunning()方法前须要在配置文件中声明ohos.permission.KEEP_BACKGROUND_RUNNING权限,同时还须要在配置文件中添加对应的backgroundModes参数。在onStop()方法中调用cancelBackgroundRunning()方法可中止前台Service。
使用前台Service的onStart()代码示例以下:
// 建立通知,其中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为建立通知时传入的notificationId keepBackgroundRunning(1005, request);
在配置文件中,“module > abilities”字段下对当前Service作以下配置:
{ "name": ".ServiceAbility", "type": "service", "visible": true, "backgroundModes": ["dataTransfer", "location"] }