前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自学HarmonyOS应用开发(57)- 与Service进行交互

自学HarmonyOS应用开发(57)- 与Service进行交互

作者头像
面向对象思考
发布2021-07-16 10:58:50
5730
发布2021-07-16 10:58:50
举报
生成一个Service之后,就需要构建一个Connection对象并通过它实现PageAbility和ServiceAbility之间的交互。

构建自己的Connection类 StopWatchServiceConnection类的主要功能有两个:一是接受连接成功通知并获取服务端传过来的用于通信的IRemoteObject对象,这是onAbilityConnectDone方法的主要工作;二是接收连接成功切断时的通知。

代码语言:javascript
复制
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之间建立沟通渠道。

代码语言:javascript
复制
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定义如下接口:

代码语言:javascript
复制
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会自动生成三个用于线程通信的辅助类。

第一个是接口定义文件:

代码语言:javascript
复制
public interface StopWatchAgent extends IRemoteBroker {

    void setCurrentTab(
        /* [in] */ int index) throws RemoteException;

    int getCurrentTab() throws RemoteException;
};

可以看到这个文件就是IDL文件的java语言实现。

第二个文件是用来将用户请求进行封装后调用IRemoteObject的功能进行线程或进程通信的StopWatchAgentProxy类。

代码语言:javascript
复制
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类:

代码语言:javascript
复制
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类可以直接实现所需功能而无需关心线程/进程通信的各种细节:

代码语言:javascript
复制
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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-07-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 面向对象思考 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档