构建自己的Connection类 StopWatchServiceConnection类的主要功能有两个:一是接受连接成功通知并获取服务端传过来的用于通信的IRemoteObject对象,这是onAbilityConnectDone方法的主要工作;二是接收连接成功切断时的通知。
public class StopWatchServiceConnection implements IAbilityConnection {
static final HiLogLabel LOG_LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00211, "StopWatchServiceConnection");
public static final int EVENT_CONNECT_DONE = 0x1000001;
public static final int EVENT_DISCONNECT_DONE = 0x1000002;
/**
* handle message from service to ability slice
*/
private static EventHandler handler = new EventHandler(EventRunner.current()) {
@Override
protected void processEvent(InnerEvent event) {
switch(event.eventId){
case EVENT_CONNECT_DONE:
break;
case EVENT_DISCONNECT_DONE:
break;
}
}
};
@Override
public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int resultCode) {
HiLog.info(LOG_LABEL, "%{public}s", "onAbilityConnectDone resultCode : " + resultCode);
InnerEvent innerEvent = InnerEvent.get(EVENT_CONNECT_DONE, resultCode, new StopWatchAgentProxy(iRemoteObject));
handler.sendEvent(innerEvent);
}
@Override
public void onAbilityDisconnectDone(ElementName elementName, int resultCode) {
HiLog.info(LOG_LABEL, "%{public}s", "onAbilityDisconnectDone resultCode : " + resultCode);
InnerEvent innerEvent = InnerEvent.get(EVENT_DISCONNECT_DONE, resultCode);
handler.sendEvent(innerEvent);
}
}
需要说明的是:由于onAbilityConnectDone和onAbilityDisconnectDone不是UI线程上下文中被调用,因此必须通过一个EventHandler进行上下文切换之后才能安全地在UI线程中使用。
使用Connection类
StopWatchServiceConnection构建完成之后,就可以使用它在PageAbility和ServiceAbility之间建立沟通渠道。
private void connectService() {
HiLog.info(LOG_LABEL, "MainAbilitySlice.connectService!");
Intent intent = getLocalServiceIntent(LOCAL_BUNDLE, FOREGROUND_SERVICE);
connection = new StopWatchServiceConnection();
connectAbility(intent, connection);
}
private Intent getLocalServiceIntent(String bundleName, String serviceName) {
Operation operation = new Intent.OperationBuilder().withDeviceId("")
.withBundleName(bundleName)
.withAbilityName(serviceName)
.build();
Intent intent = new Intent();
intent.setOperation(operation);
return intent;
}
代码第4行用到了前面构建的StopWatchServiceConnection类。
通过IRemoteObject调用Service Ability的功能
IRemoteObject作为HarmonyOS中的基础类,只提供线程通信的基本功能,开发者还需要另外定义和实现业务领域的接口。
我们使用HarmonyOS IDL定义如下接口:
interface xwg.harmony.stopwatch.StopWatchAgent {
/*
* Example of a service method that uses some parameters
*/
void setCurrentTab([in] int index);
int getCurrentTab();
boolean start();
void stop();
boolean isRunning();
long getStartTime();
long getTime();
void resetTime();
void recordTime();
String[] getLapTimes();
void registerLocationEvent();
double[] getCurrentLocation();
}
我们将这个文件加入到项目中,启动编译过程之后,DevEco Studio会自动生成三个用于线程通信的辅助类。
第一个是接口定义文件:
public interface StopWatchAgent extends IRemoteBroker {
void setCurrentTab(
/* [in] */ int index) throws RemoteException;
int getCurrentTab() throws RemoteException;
};
可以看到这个文件就是IDL文件的java语言实现。
第二个文件是用来将用户请求进行封装后调用IRemoteObject的功能进行线程或进程通信的StopWatchAgentProxy类。
public class StopWatchAgentProxy implements StopWatchAgent {
public StopWatchAgentProxy(
/* [in] */ IRemoteObject remote) {
this.remote = remote;
}
@Override
public IRemoteObject asObject() {
return remote;
}
@Override
public void setCurrentTab(
/* [in] */ int index) throws RemoteException {
MessageParcel data = MessageParcel.obtain();
MessageParcel reply = MessageParcel.obtain();
MessageOption option = new MessageOption(MessageOption.TF_SYNC);
data.writeInterfaceToken(DESCRIPTOR);
data.writeInt(index);
try {
remote.sendRequest(COMMAND_SET_CURRENT_TAB, data, reply, option);
reply.readException();
} finally {
data.reclaim();
reply.reclaim();
}
}
@Override
public int getCurrentTab() throws RemoteException {
MessageParcel data = MessageParcel.obtain();
MessageParcel reply = MessageParcel.obtain();
MessageOption option = new MessageOption(MessageOption.TF_SYNC);
data.writeInterfaceToken(DESCRIPTOR);
try {
remote.sendRequest(COMMAND_GET_CURRENT_TAB, data, reply, option);
reply.readException();
int result = reply.readInt();
return result;
} finally {
data.reclaim();
reply.reclaim();
}
}
};
代码比较长,但每个接口的套路都一样。有了使用StopWatchAgentProxy,PageAbility就可以直接调用ServiceAbility的功能,而不需要关心这些功能是在其他线程还是其他设备。
最后是一个用于帮助ServiceAbility实现接口的StopWatchAgengStub类:
public abstract class StopWatchAgentStub extends RemoteObject implements StopWatchAgent {
...
public StopWatchAgentStub(
/* [in] */ String descriptor) {
super(descriptor);
}
@Override
public IRemoteObject asObject() {
return this;
}
public static StopWatchAgent asInterface(IRemoteObject object) {
if (object == null) {
return null;
}
StopWatchAgent result = null;
IRemoteBroker broker = object.queryLocalInterface(DESCRIPTOR);
if (broker != null) {
if (broker instanceof StopWatchAgent) {
result = (StopWatchAgent)broker;
}
} else {
result = new StopWatchAgentProxy(object);
}
return result;
}
@Override
public boolean onRemoteRequest(
/* [in] */ int code,
/* [in] */ MessageParcel data,
/* [out] */ MessageParcel reply,
/* [in] */ MessageOption option) throws RemoteException {
String token = data.readInterfaceToken();
if (!DESCRIPTOR.equals(token)) {
return false;
}
switch (code) {
case COMMAND_SET_CURRENT_TAB: {
int index = data.readInt();
setCurrentTab(index);
reply.writeNoException();
return true;
}
case COMMAND_GET_CURRENT_TAB: {
int result;
result = getCurrentTab();
reply.writeNoException();
reply.writeInt(result);
return true;
}
default:
return super.onRemoteRequest(code, data, reply, option);
}
}
};
有了StopWatchAgengStub类,ServiceAbility类可以直接实现所需功能而无需关心线程/进程通信的各种细节:
StopWatchAgentStub remoteAgentStub = new StopWatchAgentStub(DESCRIPTOR) {
@Override
public void setCurrentTab(int index) throws RemoteException {
current_tab = index;
}
@Override
public int getCurrentTab() throws RemoteException {
return current_tab;
}
...
};
参考代码 完整代码可以从以下链接下载:
https://github.com/xueweiguo/Harmony/tree/master/StopWatch
参考资料:
接口描述语言简介
https://developer.harmonyos.com/cn/docs/documentation/doc-references/idl-overview-0000001050762835