HarmonyOS-Service

HarmonyOS does not provide a separate Service class. The Service in this article is based on the Ability of the Service template. This article focuses on the differences and relationships between HarmonyOS Service and Android Service. Both services are summarized as follows:

An overview of the
HarmonyOS It is used to perform background tasks, such as playing music and downloading files, 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.
Android An application component that runs operations in the background for a long time without providing an interface. Services can be started by other application components and continue to run in the background even if the user switches to another application. In addition, components can interact with services by binding to them and even perform interprocess communication (IPC). For example, a service can process network transactions, play music, perform file I/O, or interact with content providers in the background.
Service of the two systems is basically the same in terms of definition, function and usage. Most of them are used for background running tasks without providing an interface. They can be cross-application or cross-thread. They are mainly used for performing tasks such as music playing and file downloading. A Service is a singleton that can be created or destroyed. If you want to share a Service, you must enable multiple threads. Otherwise, threads will block and programs will not respond. HarmonyOS Service is cross-process and cross-device, while Android Service is cross-process and cross-device.
The two services are defined in code but have essential differences, as shown in the following figure:
Service Ability and Page Ability are divided according to function. HarmonyOS does not provide a separate parent class for them. Both are elements of Ability, although Ability implements Context, Context is defined by interface:

public interface Context {
    int CONTEXT_IGNORE_SECURITY = 2; . }Copy the code

This is quite different from Android, where Context is abstract:

public abstract class Context {
    / * *@hide* /
    @IntDef(flag = true, prefix = { "MODE_" }, value = { MODE_PRIVATE, ... }). }Copy the code

This means that HarmonyOS’s service and interface are one, whereas Android’s service and interface are separate. Looking at the open application development code HarmonyOS currently has, it’s clear that it uses interfaces more than Android does, making the code lightweight, convenient and flexible. Compared to Android, HarmonyOS Ability has only one parent class, AbilityContext, and a single level of functionality. Although simple, HarmonyOS Ability currently supports limited, or even unitary, apis, which are not conducive to development. Android has many layers, and the code execution efficiency is relatively slow. Although it seems that the code is nested too much, or even redundant, it provides rich Api, which is convenient for developers to develop. HarmonyOS uses a common Context regardless of the Context. In Android, Context is classified into activities, services, and applications. Therefore, errors may be reported when using Context or this, mainly because the Context type is inconsistent.

The life cycle

Both HarmonyOS and Android have the same Service life cycle, as follows:

Depending on how the Service is invoked, both Service life cycles can be broken down into normal and connected services (HarmonyOS refers to them as connected services, Android as bound services).

  • General services: general background services, such as map location, file download, etc.
  • ConnectAbility Service: 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.

HarmonyOS Service and Android Service are divided into background Service, foreground Service, and binding (connection) Service, depending on the application scenario.

  • Background services: Background services perform operations that users do not notice directly. 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.
  • Front Desk services: Front desk services perform operations that users notice. 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.
  • Binding service: A binding service is a server in a client-server interface. By binding services, components (such as activities) can bind to services, send requests, receive responses, and perform interprocess communication (IPC). Binding services are typically active only when serving other application components and do not run in the background indefinitely.

Regardless of the type of service, services can exist independently or co-exist, that is, with both foreground and binding services, or in some other combination. The two services not only have the same life cycle, but also have the same cycle status, as shown in the following table:

HarmonyOS Android
onStart() onCreate()
onCommand() onStartCommand()
onConnect() onBind()
onDisconnect() onUnbind()
onStop() onDestroy()
The HarmonyOS:
“`java
public class HarmonyOSService 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) {
    super.onConnect(intent);
    return null;
}

@Override
public void onDisconnect(Intent intent) {
    super.onDisconnect(intent);
}

@Override
public void onStop() {
    super.onStop();
}
Copy the code

}

AndroidService extends Service {@override public void onCreate() {super.oncreate (); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public boolean onUnbind(Intent intent) { return super.onUnbind(intent); } @Override public void onDestroy() { super.onDestroy(); }}Copy the code

Initialization:

  • OnStart () : called by HarmonyOS when a Service is created. It is used to initialize the Service and is called only once during the life of the Service.
  • OnCreate () : When Android first creates a service, the system calls this method (before calling onStartCommand() or onBind()) to perform a one-time setup. This method is not called if the service is already running.

Activation:

  • OnCommand () : HarmonyOS is called when a Service is created. This method is called every time the client starts the Service. You can use this method to call statistics and initialize classes.
  • OnStartCommand () : In Android, the system calls startService() when another component (such as an Activity) requests to start a service. When this method is executed, the service is started and can run in the background indefinitely. Implementing this method stops the service by calling stopSelf() or stopService() after the service work is complete. (You don’t need to implement this method if you just want to bind.)

Binding:

  • OnConnect () : Called in HarmonyOS when Ability and Service are connected. This method returns the IRemoteObject and allows the user to generate an IPC channel for the Service to communicate with it. 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.
  • OnBind () : Android calls this method by calling bindService() when another component wants to bind to a service (for example, to execute RPC). In the implementation of this method, the developer must provide an interface that the client can use to communicate with the service by returning the IBinder. Be sure to implement this method; However, if the developer does not wish to allow binding, null should be returned.

Unbundling:

  • OnDisconnect () : called in HarmonyOS when Ability disconnects from the bound Service.
  • OnUnbind () : On Android the client can close the connection by calling unbindService(). Multiple clients can be bound to the same service, and when all bindings are removed, the system destroys the service. (The service does not have to stop running on its own.)

Destruction:

  • OnStop () : called in HarmonyOS 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.
  • OnDestroy () : This method is called in Android when a service is no longer in use and is ready to be destroyed. The service should implement this method to clean up any resources, such as threads, registered listeners, sinks, and so on. This is the last call received by the service.

In summary, HarmonyOS and Android share the same Service lifecycle and method calls and functions.

use

Create a Service

HarmonyOS: Create a subclass of Ability to implement service-related lifecycle methods. Service is also Ability, and users can override these methods to add their own processing.

public class HarmonyOSService extends Ability {
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent); }... }Copy the code

Android: Create a subclass of Service (or use an existing subclass of it). Developers need to rewrite callback methods to address some key aspects of the service life cycle and provide a mechanism to bind components to services.

public class AndroidService extends Service {
    @Override
    public void onCreate(a) {
        super.onCreate(); }... }Copy the code

Or create an IntentService (Service subclass) subclass that executes all requests to start the Service serially.

public class AndroidIntentService extends IntentService {

  public AndroidIntentService(a) {
      super("AndroidIntentService");
  }
  @Override
  protected void onHandleIntent(Intent intent) {
      try {
          Thread.sleep(5000);
      } catch (InterruptedException e) {
          // Restore interrupt status.Thread.currentThread().interrupt(); }}}Copy the code

registered

HarmonyOS: Service 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

Android: Developers must declare all services in the application’s manifest file. To declare a service, you need to add an element as a child of the element, and the name attribute is the only required attribute.

<manifest . >.<application . >
      <service android:name=".AndroidService" />.</application>
</manifest>
Copy the code

Start the service

HarmonyOS

Ability in HarmonyOS 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. Start local services as follows:

Intent intent = new Intent();
Operation operation = new Intent.OperationBuilder()
        .withDeviceId("")
        .withBundleName("com.huawei.hiworld.himusic")
        .withAbilityName("com.huawei.hiworld.himusic.entry.ServiceAbility")
        .build();
intent.setOperation(operation);
startAbility(intent);
Copy the code

Parameter Description:

  • 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.
  • BundleName: indicates the package name.
  • AbilityName: indicates the name of the Ability to be enabled.

Start the remote service as follows:

Operation operation = new Intent.OperationBuilder()
        .withDeviceId("deviceId")
        .withBundleName("com.huawei.hiworld.himusic")
        .withAbilityName("com.huawei.hiworld.himusic.entry.ServiceAbility")
        .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE) // Set the identifier that supports the multi-device startup of the distributed scheduling system
        .build();
Intent intent = new Intent();
intent.setOperation(operation);
startAbility(intent);
Copy the code

Ability starts 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.

Android

A developer can start a service from an Activity or other application component by passing the Intent to startService() or startForegroundService(). The Android system calls the service’s onStartCommand() method and passes it an Intent to specify which service to start. If the application is API level 26 or higher, there are no restrictions on the use or creation of background services unless the application itself is running in the foreground. If an application needs to create a foreground service, it should call startForegroundService(). This method creates a background service, but it signals to the system that the service will be promoted to the foreground on its own. After the service is created, it must call its startForeground() method within five seconds.

Intent intent = new Intent(this, AndroidService.class);
startService(intent);
Copy the code

The startService() method returns immediately, and the Android system calls the service’s onStartCommand() method. If the service is not already running, onCreate() is first called, followed by onStartCommand(). If the service also does not provide bindings, the only mode of communication between the application component and the service is an Intent passed by startService(). However, if the developer wants the service to return a result, the client that started the service can create a PendingIntent for the broadcast (obtained via getBroadcast()) and pass it to the service in the Intent that started the service. The service can then use broadcasts to deliver the results. Multiple service start requests result in multiple calls to the service’s onStartCommand(). However, to stop the service, only a service stop request (using stopSelf() or stopService()) is required.

Start the Foreground service (optional)

HarmonyOS

The developer simply needs to bind the Service to the notification by calling keepBackgroundRunning() in the Service creation method. The keepBackgroundRunning() method needs to be declared in the configuration file before it is called. KEEP_BACKGROUND_RUNNING Permission. The permission is normal and the corresponding backgroundModes parameters need to be added to 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

Configure the following parameters in the configuration file:

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

To create the foreground service, call startForeground(). This method also requires notificationId and Notification instances:

Intent notificationIntent = new Intent(this, AndroidActivity.class);
PendingIntent pendingIntent =
        PendingIntent.getActivity(this.0, notificationIntent, 0);

Notification notification =
          new Notification.Builder(this. CHANNEL_DEFAULT_IMPORTANCE) .setContentTitle(getText(R.string.notification_title)) .setContentText(getText(R.string.notification_message)) .setSmallIcon(R.drawable.icon) .setContentIntent(pendingIntent) .setTicker(getText(R.string.ticker_text)) .build(); startForeground(ONGOING_NOTIFICATION_ID, notification);Copy the code

Note: Notification ID cannot be 0. FOREGROUND_SERVICE permission is required to obtain foreground services in Android 9 (API Level 28).

<manifest xmlns:android="http://schemas.android.com/apk/res/android" .>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <application .>.</application>
</manifest>
Copy the code

If the application target level is higher than Android 10 (API Level 29), declare the relevant foreground service type in the manifest file:

<manifest>.<service . android:foregroundServiceType="location|camera" />
</manifest>
Copy the code

Also declare in the code:

Notification notification = ... ; Service.startForeground(notification, FOREGROUND_SERVICE_TYPE_LOCATION | FOREGROUND_SERVICE_TYPE_CAMERA);Copy the code

Binding services (optional)

HarmonyOS

If a Service needs to interact with Page Ability or the Service Ability of another application, then a Connection should 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() to handle connection callbacks and onAbilityDisconnectDone() to handle disconnected callbacks.

// Create a connection callback instance
private IAbilityConnection connection = new IAbilityConnection() {
    // Connect to the Service callback
    @Override
    public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int resultCode) {
        // Here the developer can get the IRemoteObject from the server and parse the information from it
    }
 
    // Disconnect the connection callback
    @Override
    public void onAbilityDisconnectDone(ElementName elementName, int resultCode) {}};/ / connection Service
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 the RemoteObject. 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 RemoteObject {
    public MyRemoteObject(a) {
        super("MyRemoteObject"); }}// Return IRemoteObject to the client
@Override
protected IRemoteObject onConnect(Intent intent) {
    return new MyRemoteObject();
}
Copy the code
Android

A binding service is a server in a client-server interface. By binding services, components (such as activities) can bind to services, send requests, receive responses, and perform interprocess communication (IPC). Binding services are typically active only when serving other application components and do not run in the background indefinitely. When creating a service that provides bindings, you must provide the IBinder, which in turn provides a programming interface that clients can use to interact with the service. Developers can define interfaces in three ways: by extending Binder classes, using Messenger, and (generally not) using AIDL.

  • Extend the Binder class. Create code as follows:
public class LocalService extends Service {
    private final IBinder binder = new LocalBinder();
    private final Random mGenerator = new Random();
    
    public class LocalBinder extends Binder {
        LocalService getService(a) {
            return LocalService.this; }}@Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    public int getRandomNumber(a) {
      return mGenerator.nextInt(100); }}Copy the code

Boot as follows:

public class BindingActivity extends Activity {
    LocalService mService;
    boolean mBound = false;

    @Override
    protected void onStart(a) {
        super.onStart();
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop(a) {
        super.onStop();
        unbindService(connection);
        mBound = false;
    }
    public void onButtonClick(View v) {
        if (mBound) {
            intnum = mService.getRandomNumber(); . }}private ServiceConnection connection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false; }}; }Copy the code
  • Use the Messenger. Create code as follows:
public class MessengerService extends Service {
    static final int MSG_SAY_HELLO = 1;

    static class IncomingHandler extends Handler {
        private Context applicationContext;

        IncomingHandler(Context context) {
            applicationContext = context.getApplicationContext();
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                  ...
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
    Messenger mMessenger;
    @Override
    public IBinder onBind(Intent intent) {... mMessenger =new Messenger(new IncomingHandler(this));
        returnmMessenger.getBinder(); }}Copy the code

The service receives the incoming Message in the Handler’s handleMessage() method and decides what to do next based on the WHAT member. The client simply creates the Messenger based on the IBinder returned by the service and sends the message using Send (). For example, the following simple Activity shows how to bind to a service and pass an MSG_SAY_HELLO message to the service:

public class ActivityMessenger extends Activity {
    Messenger mService = null;
    boolean bound;

    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            mService = new Messenger(service);
            bound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            mService = null;
            bound = false; }};public void sayHello(View v) {
        if(! bound)return;
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0.0);
        try {
            mService.send(msg);
        } catch(RemoteException e) { e.printStackTrace(); }}@Override
    protected void onStart(a) {
        super.onStart();
        bindService(new Intent(this, MessengerService.class), mConnection,
            Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop(a) {
        super.onStop();
        if (bound) {
            unbindService(mConnection);
            bound = false; }}}Copy the code

Application components (clients) can bind to services by calling bindService(). The Android system then calls the service’s onBind() method, which returns the IBinder used to interact with the service. Bind to an asynchronous operation, and bindService() returns immediately without having to return the IBinder to the client. To receive IBinder, the client must create an instance of ServiceConnection and pass it to bindService(). ServiceConnection contains a callback method that the system calls to pass the IBinder. Only activities, services, and content providers can be bound to services, not broadcast receivers. The client bound to the service must perform the following steps:

  1. Realize the ServiceConnection. Overwrite onServiceConnected() and onServiceDisconnected().
  2. Call bindService(), passing the ServiceConnection implementation.
  3. When the system calls the onServiceConnected() callback method, a developer can use the interface’s defined methods to start invoking the service.
  4. To disconnect from the service, call unbindService().

HarmonyOS Service is significantly easier and more convenient to bind to than Android Service. Android offers three options depending on the application scenario, but it can be complicated to use, especially in advanced versions. To sum up, each has its pros and cons.

Unbinding Service (optional)

  • HarmonyOS: A Service can be stopped by terminateAbility() or by calling stopAbility() from any other Ability.
  • Android: Disconnect from the service by calling unbindService().

The destruction

  • HarmonyOS: Ability To stop Service or disconnectAbility() by calling stopAbility(). Once the Service has stopped, it will be destroyed by the system.
  • Android: If a component starts a service by calling startService(), the service will run until it stops itself with stopSelf() or is stopped by another component by calling stopService().

conclusion

HarmonyOS Service and Android Service are not very different from each other in terms of method definition, lifecycle, method invocation, etc. When it comes to binding services, Android implements them in more varied ways and is a bit more complex to use. Overall, HarmonyOS is simple and efficient, while Android is rich and flexible. It is meaningless to judge who is superior and who is inferior if it is separated from actual application scenarios.

instructions

  • The HarmonyOS related material in this article comes from the HarmonyOS Developer documentation.
  • The Android related materials in this article are taken from the Android Developer development guide.
  • For infringement or error, please send an email to [email protected].