Service Ability

Basic concepts of Service Ability

The Ability based on the Service template (” Service “) is mainly used for background running tasks (such as performing music playback, file download, etc.), but does not provide a user interface. A Service can be started by another application or Ability and will continue to run in the background even if the user switches to another application.

A Service is singleton. There is only one instance of the same Service on a device. If multiple Ability shares this instance, a Service can exit only when all Ability bound to it exits. Since a Service is executed in the main thread, if the operation takes too long in the Service, the developer must create a new thread in the Service to prevent the main thread from blocking and the application from becoming unresponsive.

Create a Service

This section describes how to create a Service. Create a subclass of Ability to implement service-related lifecycle methods. Service is also Ability. Ability provides the following lifecycle methods for Service, which can be overridden to add other Ability requests that interact with Service Ability.

  • onStart()

This method is called when a Service is created and is used to initialize the Service. The Service is called only once during its lifetime, and the incoming Intent should be null.

  • onCommand()

Called after a Service is created. This method is called every time the client starts the Service. Users can perform operations such as calling statistics and initializing classes in this method.

  • onConnect​()

Called when Ability and Service are connected, this method returns the IRemoteObject, and the user can generate an IPC communication channel for the corresponding Service in this callback function so that Ability can interact with the Service. Ability can connect to the same Service multiple times. The IPC object of the Service is cached. Only when the first client connects to a Service does the onConnect method of the Service generate the IRemoteObject. The same RemoteObject is then passed to all other clients connected to the same Service without calling onConnect again.

  • onDisconnect​()

Called when Ability is disconnected from a bound Service.

  • onStop()

Called when a Service is destroyed. The Service should implement this method to clean up any resources, such as closing threads, registered listeners, and so on. The following is an example of code for creating a 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(a) {
        super.onStop(); }}Copy the code

2. Register Service. Service also needs to be registered in the application configuration file. The registration type must be set to Service.

{
    "module": {
        "abilities": [{"name": ".ServiceAbility"."type": "service"."visible": true. }]... }... }Copy the code

Start the Service

This section describes how to start the Service using startAbility() and how to stop it.

  • Start the Service

Ability provides the startAbility() method for developers to initiate another Ability. Since Service is also a type of Ability, a developer can also launch a Service by passing an Intent to that method. Support to start not only local services, but also remote services. Developers can set the target Service information by constructing Operation objects containing DeviceId, BundleName, and AbilityName. The meanings of the three parameters are as follows: – DeviceId: indicates the DeviceId. If the device is a local device, you can leave it blank. . If it is a remote device, by ohos distributedschedule. Interwork. DeviceManager getDeviceList access equipment list, see the API reference. – BundleName: indicates the package name. – AbilityName: indicates the name of the Ability to be enabled.

The following is an example of code for starting a local device 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);
Copy the code

The following is an example of code for starting a remote device 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) // Set the identifier that supports the multi-device startup of the distributed scheduling system
        .build();
intent.setOperation(operation);
startAbility(intent);
Copy the code

After executing the above code, Ability will start the Service with the startAbility() method.

  • If the Service is not already running, the system calls onStart() to initialize the Service and then calls its onCommand() method to start the Service.

  • If the Service is running, the system directly calls back to the Service’s onCommand() method to start the Service.

  • Stop the Service

Once created, a Service runs in the background and is not stopped or destroyed unless memory resources must be reclaimed. The developer can stop a Service by terminateAbility() or by calling stopAbility() from other Ability. Stopping Service You can also stop local device Service and remote device Service in the same way as starting Service. Once the stop Service method is called, the system destroys the Service as soon as possible.

Connect the Service

If a Service needs to interact with Page Ability or the Service Ability of another application, then a Connection must be created for the Connection. Service supports other abilities connected to it by connectAbility().

To handle a callback using connectAbility(), you need to pass in the Intent and IAbilityConnection instances of the target Service. IAbilityConnection provides two methods for developers to implement: onAbilityConnectDone() is used to handle the callback for the successful connection to the Service, and onAbilityDisconnectDone() is used to handle the callback for the abnormal death of the Service.

The following is an example of code for creating a connection Service callback instance:

// Create a connection Service callback instance
private IAbilityConnection connection = new IAbilityConnection() {
    // Connect to the Service callback
    @Override
    public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int resultCode) {
        // The Client side needs to define the same IRemoteObject implementation class as the Service side. The developer gets the IRemoteObject from the server and parses the information from it.
    }

    // Callback for Service exception death
    @Override
    public void onAbilityDisconnectDone(ElementName elementName, int resultCode) {}};Copy the code

The following is an example of code for connecting to a Service:

/ / connection 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);
Copy the code

The Service side also needs to return the IRemoteObject on onConnect() to define the interface to communicate with the Service. HarmonyOS provides a default implementation of IRemoteObject. You can create custom implementation classes by inheriting from LocalRemoteObject. The following is an example of code for the Service side to return an instance of itself to the calling side:

// Create a custom IRemoteObject implementation class
private class MyRemoteObject extends LocalRemoteObject {
    MyRemoteObject(){
    }
}

// Return IRemoteObject to the client
@Override
protected IRemoteObject onConnect(Intent intent) {
    return new MyRemoteObject();
}
Copy the code

Service Ability lifecycle

Like Page, a Service has a life cycle, as shown in Figure 1. Depending on the method called, there are two paths to its life cycle:

  • Start the Service

This Service is created when startAbility() is called by other abilities and then left running. Stop a Service by calling stopAbility(). When a Service stops, it is destroyed.

  • Connect the Service

This Service is created when other abilities call connectAbility(), and clients can be disconnected by calling disconnectAbility(). Multiple clients can be bound to the same Service, and when all bindings are cancelled, the system destroys the Service.

Figure 1 Service life cycle

The front desk Service

In most cases, services run in the background and have a low priority. When resources are insufficient, the system may reclaim the running background services.

In some scenarios, such as playing music, where the user wants the application to keep running, foreground services are needed. The foreground Service always keeps the running icon in the system status bar.

Using a foreground Service is not complicated. The developer simply needs to bind the Service to the notification by calling keepBackgroundRunning() in the Service creation method. Before calling keepBackgroundRunning(), declare the ohos.permission-keep_background_RUNNING permission in the configuration file, and add the corresponding backgroundModes in the configuration file. The cancelBackgroundRunning() method is called in the onStop() method to stop the foreground Service.

Example code for onStart() using the foreground Service is as follows:

// Create notification with 1005 as 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);

// Bind the notification, 1005 is the notificationId passed in when the notification is created
keepBackgroundRunning(1005, request);
Copy the code

In the configuration file, the current Service is configured as follows under “Module > Abilities” :

{    
    "name": ".ServiceAbility"."type": "service"."visible": true."backgroundModes": ["dataTransfer"."location"]}Copy the code