评论

收藏

[HarmonyOS] HarmonyOS学习路之开发篇——Service Ability

移动开发 移动开发 发布于:2021-06-28 14:20 | 阅读数:544 | 评论:0

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 {
  @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、注册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的回调
  @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生命周期 DSC0000.jpg
前台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"]
}
关注下面的标签,发现更多相似文章