[Huawei Developers] shikkerimath:
Introduction

In this article, we can create an application showing below features:

1. Service Ability

2. Create service ability

3. Connect page ability with service ability

4. Update result on UI received from service ability

Requirements

1. DevEco IDE

2. Wearable watch (Can use simulator also)

Harmony OS Supports two types of abilities

1. Feature Ability

2. Particle Ability

In this article, we will test Particle Ability template called Service template.

UI Design

View attachment 5251519

Service Template (Service Abilities):

The Service template is used for Particle Ability that provide background tasks.

A Service ability has only one instance on a device and multiple abilities share this instance.

Service Abilities runs on Main thread, you must create another thread for that operation in the Service ability.

Life cycle methods can be find here:

Document

developer.harmonyos.com

Main uses, it can be used in playing music or downloading files or any other background tasks which doesn’t need UI.

Create Service Ability:

It has two steps:

1. Register ability in config.json

2. Create service class extending Ability

Add the below code in Config.json

{
"app": {
"bundleName": "com.example.testserviceability",
"vendor": "example",
"version": {
"code": 1,
"name": "1.0"
},
"apiVersion": {
"compatible": 3,
"target": 3
}
},
"deviceConfig": {},
"module": {
"package": "com.example.testserviceability",
"name": ".MyApplication",
"deviceType": [
"wearable"
],
"distro": {
"deliveryWithInstall": true,
"moduleName": "entry",
"moduleType": "entry"
},
"abilities": [
{
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
],
"orientation": "landscape",
"name": "com.example.testserviceability.MainAbility",
"icon": "$media:icon",
"description": "$string:mainability_description",
"label": "TestServiceAbility",
"type": "page",
"launchType": "standard"
},
{
"name": ".ServiceAbility",
"type": "service",
"visible": true
}
]
}
}

Add the below code in ServiceAbility.java

package com.example.testserviceability;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.LocalRemoteObject;
import ohos.aafwk.content.Intent;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.rpc.IRemoteObject;

public class ServiceAbility extends Ability {
static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0x00201, "MY_TAG");

@Override
public void onStart(Intent intent) {
super.onStart(intent);
HiLog.info(LABEL_LOG, "inside onStart!!");
}

@Override
public void onCommand(Intent intent, boolean restart, int startId) {
super.onCommand(intent, restart, startId);
HiLog.info(LABEL_LOG, "inside onCommand!!");
}

@Override
public IRemoteObject onConnect(Intent intent) {
super.onConnect(intent);
HiLog.info(LABEL_LOG, "inside onConnect!!");
//return super.onConnect(intent);
return new MyRemoteObject();
}

String sayHello(String name){
return "Hello "+name;
}

@Override
public void onDisconnect(Intent intent) {
super.onDisconnect(intent);
HiLog.info(LABEL_LOG, "inside onDisconnect!!");
}

@Override
public void onStop() {
super.onStop();
HiLog.info(LABEL_LOG, "inside onStop!!");
}

public class MyRemoteObject extends LocalRemoteObject {
public MyRemoteObject() {
super();
}

public String callHello(String name){
return sayHello(name);
}
}
}

Connect Page Ability with Service Ability:

This can be done using LocalRemoteObject, like shown below.

Add the below code in MainAbilitySlice.java

package com.example.testserviceability.slice;

import com.example.testserviceability.ResourceTable;
import com.example.testserviceability.ServiceAbility;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.ability.IAbilityConnection;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.bundle.ElementName;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.rpc.IRemoteObject;

public class MainAbilitySlice extends AbilitySlice {
static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0x00201, "MY_TAG");

ServiceAbility.MyRemoteObject myRemoteObject;
Text text;

@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
text = (Text) findComponentById(ResourceTable.Id_text);
Button btnStartService = (Button) findComponentById(ResourceTable.Id_button_start_service);
btnStartService.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
startBackGroundService();
}
});

Button btnCallServiceFunction = (Button) findComponentById(ResourceTable.Id_button_call_service_function);
btnCallServiceFunction.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
if(myRemoteObject != null){
String valueFromService = myRemoteObject.callHello("pavan");
HiLog.info(LABEL_LOG, "valueFromService-->"+valueFromService);
text.setText(valueFromService);
}else{
HiLog.info(LABEL_LOG, "myRemoteObject is null!!");
}
}
});
}

@Override
public void onActive() {
super.onActive();
}

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

private void startBackGroundService(){
HiLog.info(LABEL_LOG, "inside startBackGroundService!!");
Intent intent = new Intent();
Operation operation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName("com.example.testserviceability")
.withAbilityName("com.example.testserviceability.ServiceAbility")
.build();
intent.setOperation(operation);
connectAbility(intent, connection);
}

// Create an IAbilityConnection instance.
private IAbilityConnection connection = new IAbilityConnection() {
// Override the callback invoked when the Service ability is connected.
@Override
public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int resultCode) {
// The client must implement the IRemoteObject interface in the same way as the Service ability does. You will receive an IRemoteObject object from the server and can then parse information from it.
myRemoteObject= (ServiceAbility.MyRemoteObject) iRemoteObject;
HiLog.info(LABEL_LOG, "service connection made successful!!");
}

// Override the callback invoked when the Service ability is disconnected.
@Override
public void onAbilityDisconnectDone(ElementName elementName, int resultCode) {
}
};
}

Add the below code in ability_main.xml

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:orientation="vertical"
ohos:background_element="#8c7373"
ohos:padding="32">

<Text
ohos:multiple_lines="true"
ohos:id="$+id:text"
ohos:height="match_content"
ohos:width="200"
ohos:layout_alignment="horizontal_center"
ohos:text="Text"
ohos:text_size="10fp"/>

<Button
ohos:id="$+id:button_start_service"
ohos:height="match_content"
ohos:width="match_content"
ohos:background_element="$graphic:background_button"
ohos:layout_alignment="horizontal_center"
ohos:padding="5"
ohos:text="Start service"
ohos:text_size="30"
ohos:top_margin="5"/>

<Button
ohos:id="$+id:button_call_service_function"
ohos:height="match_content"
ohos:width="match_content"
ohos:background_element="$graphic:background_button"
ohos:layout_alignment="horizontal_center"
ohos:padding="5"
ohos:text="Call service function"
ohos:text_size="30"
ohos:top_margin="5"/>

</DirectionalLayout>

Connect Page ability with Service ability

private void startBackGroundService(){
HiLog.info(LABEL_LOG, "inside startBackGroundService!!");
Intent intent = new Intent();
Operation operation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName("com.example.testserviceability")
.withAbilityName("com.example.testserviceability.ServiceAbility")
.build();
intent.setOperation(operation);
connectAbility(intent, connection);
}

Call function of service from page ability

Button btnCallServiceFunction = (Button) findComponentById(ResourceTable.Id_button_call_service_function);
btnCallServiceFunction.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
if(myRemoteObject != null){
String valueFromService = myRemoteObject.callHello("pavan");
HiLog.info(LABEL_LOG, "valueFromService-->"+valueFromService);
text.setText(valueFromService);
}else{
HiLog.info(LABEL_LOG, "myRemoteObject is null!!");
}
}
});

Tips and Tricks

1. All Abilities must be registered into Config.json.

2. Service Ability runs on main thread, you must create other thread to handle work.

Conclusion

In this article, we have UI components communicating with background running service. Calling a function of background service and getting result back on UI.

Reference

1. Harmony Official document

2. DevEco Studio User guide

3. JS API Reference

Checkout in forum