专栏首页C++核心准则原文翻译自学HarmonyOS应用开发(57)- 与Service进行交互

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

生成一个Service之后,就需要构建一个Connection对象并通过它实现PageAbility和ServiceAbility之间的交互。

构建自己的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

本文分享自微信公众号 - 面向对象思考(OOThinkingDalian),作者:面向对象思考

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-07-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 自学HarmonyOS应用开发(56)- 用Service保证应用在后台持续运行

    关于重写的几个方法的详细信息,请参照文后链接【创建Service】;startForground和cancelBackgroundRunning方法用于开启和关...

    面向对象思考
  • 自学HarmonyOS应用开发(48)- Tablist组件进阶

    但是有一个问题是这篇文章,包括HarmonyOS应用开发的官方文档都只是实现了Tab切换的基本功能,对于每个Tab页内组件的处理没有详细说明。本文就来补上这个短...

    面向对象思考
  • HarmonyOS-对Android开发者也太友好了吧

    2020年9月10日,华为消费者业务软件部总裁王成录又一次站在了松山湖华为开发者大会的主舞台上。今年,他带来了万众瞩目的华为鸿蒙HarmonyOS2.0...

    Android扫地僧
  • 技术分析 | HarmonyOS到底是不是Android套皮?

    最近鸿蒙系统关注度好高,支持与反对、看好和看衰、「自主的全场景分布式系统」和「Android套壳」各执一词,吵的不可开交。

    刘盼
  • HarmonyOS与Android的全面对比

    第二是我个人非常看好鸿蒙系统的未来,清楚明白华为和一些民族企业担负的责任和国人的期待,虽然带着一些民族感情;鸿蒙刚发布的时候自己是非常激动的,但是后来项目太忙一...

    肉眼品世界
  • HarmonyOS简介

    前两天,华为发布了HarmonyOS 2.0,俺也赶个时髦,给大家简单介绍下HarmonyOS。

    xiangzhihong
  • 十问华为HarmonyOS:开源一个月,开发者生态建设进度如何?

    基础软件的开源面临着非常大的挑战,除了技术研发困难重重,开源生态和社区的建设更是难上加难。9 月 10 日,在华为开发者大会 2020 上,华为消费者业务 CE...

    深度学习与Python
  • 带你了解鸿蒙开发基本流程

    2020年9月10号,鸿蒙2.0(HarmonyOS 2.0)系统正式发布,鸿蒙2.0面向应用开发者发布Beta版本,

    Python进击者
  • 我的HarmonyOS实战——鸿蒙系统初定义

    鸿蒙并不是一个单纯的手机操作系统,而是手机+智能设备的总称。可以安装在包括手机、手表、无人机等很多设备上。

    天道Vax的时间宝藏
  • 鸿蒙从窗口开始:Page Ability诞生记

    Page Ability是FA唯一支持的Ability,本质上是一个窗口,类似于Android的Activity,用于提供与用户交互的能力。为了方便,在后面的内...

    蒙娜丽宁
  • 【HarmonyOS 专题】01 基础 Mac 环境安装配置

    HarmonyOS 已于 2020 年 12 更新到 2.0 版本;和尚周围的人都在学习和研究,和尚也想学习一下;今天和尚从 0 开始学习,第一步简单介绍基础...

    阿策小和尚
  • 华为回应:谷歌改用AAB格式 HarmonyOS无影响

    谷歌方面曾于日前宣布(再见,APK, 你好,AAB !),Google Play 将从 2021 年 8 月开始要求新发布的应用程序以 Android App ...

    开发者技术前线
  • 【第22期】HarmonyOS应用开发(基础篇)

    这不就是说,以后华为手机都是鸿蒙系统了嘛?鸿蒙还发出了一条视频,视频中显示2021年6月2号将开启鸿蒙操作系统及华为全场景新品发布会。预计现在支持EMUI11升...

    siberiawolf
  • 【HarmonyOS 专题】02 搭建简单登录页面

    和尚在搭建完 HarmonyOS 环境之后,有很长时间没有研究过 HarmonyOS,DevEco Studio 已经更新了多个版本,和尚在升级完 ID...

    阿策小和尚
  • 前端视角看HarmonyOS

    公元 2021 年 6 月 2 日,【 HarmonyOS2.0 】正式发布,以 JavaScript 作为 IoT 应用开发的架构语言,这是继 SpaceX ...

    公众号@魔术师卡颂
  • 牛掰了!鸿蒙与Android完美融合,将鸿蒙设备当Android设备用

    1. 你看着是鸿蒙,其实它是Android,你看着是Android,其实它是鸿蒙

    蒙娜丽宁
  • 华为鸿蒙生态的目标:市占率16%以上,跨过生死线

    9 月 10 日,华为正式推出 鸿蒙 OS 2.0 版本(HarmonyOS 2.0),并宣布将 Harmony OS 的代码捐赠给开放原子开源基金会进行开源孵...

    深度学习与Python
  • 自学鸿蒙应用开发(41)- 真机调试之准备调试证书

    启动DevEco Stduio之后,通过主菜单选择Build->Generate Key and CSR。

    面向对象思考
  • 搭建鸿蒙编译环境(VMware+Linux)

    分布式软总线是多种终端设备的统一基座,为设备之间的互联互通提供了统一的分布式通信能力,能够快速发现并连接设备,高效地分发任务和传输数据。分布式软总线示意图见。

    跋扈洋

扫码关注云+社区

领取腾讯云代金券