鸿蒙HarmonyOS到底跟android有什么不同呢?

鸿蒙最大的不同点在于它是为万物互联而出生的,而不仅仅是为了手机而生,最核心优势就是它的分布式开发。那么到底什么是鸿蒙分布式?它有什么不可替代的价值?它又如何开发呢?小编将在本篇为大家一一解密。

首先来看鸿蒙官网一个案例图吧,这个案例讲的是一个用户用手机打车软件叫了网约车,然后把手机装兜里,抬手在手表上可以看车辆应答进展,手机与手表之间的信息是无缝切换的,如同一个设备两个屏幕一样,这就是分布式的最好体现。所以通俗来讲,所谓分布式,就是在不同设备之间实时协同工作,如同一个大设备不同模块一样能紧密配合。这种跨设备协同能力,与传统的android系统不一样,传统android设备之间需要多个app约定好协议才能搜索、发现、配对后联机工作。而harmonyos是直接在系统层支持了多设备间的发现、连接,对应用来说只用调用简单的接口,就可以实现分布式运行在多个设备上进行高效协同。未来科幻电影里的智能家居场景,就需要鸿蒙这样的操作系统才能支撑,这也是鸿蒙能够弯道超车安卓的一大潜在机遇。

手机手表协同叫车

好,说了鸿蒙分布式的含义和价值后,我们直接上代码,带领大家来体验一下如何开发分布式应用吧。在New Project时,选择News Feature Ability这个模板,这个模板是一个新闻信息流页面,包含一个新闻列表页和一个新闻详情页。这个demo的Ability如何布局、列表List如何用MVC实现等等,由于在上篇电商demo里已经解析过,这里就不详细说了。我们直接找到最核心的分布式代码。

创建demo工程

第一步,先看看config.json文件,这个文件跟android里的mainfest.xml一样,是定义一些ability属性及所需权限的,这里面有三个非常重要的权限,它表示是否允许本app访问和监听其它分布式设备。

{

  "name": "ohos.permission.DISTRIBUTED_DATASYNC"

},

{

  "name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"

},

{

  "name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"

},

第二步,分布式嘛,肯定是要一个设备连接访问另一个设备,在鸿蒙里,我们可以把本机叫做客户端,把要连接的目标设备叫服务端,那么客户端与服务端是两个独立的进程,如何通信呢?鸿蒙采用了流行的proxy/stub模式,即代理存根模式。

通过IDL(接口定义语言)定义设备间通信的接口,然后用工具自动生成对应的proxy和stub文件,其中proxy运行在客户端,stub运行在服务端,他们像是中介一样,连接着客户端和服务端。

代理和存根

代理框架图

我们从上面截图里可以看到,IDL里只有一个接口,就是transShare(),它有5个参数,从变量名称我们大概可以猜到其含义是设备ID、新闻网址、新闻标题、新闻摘要、新闻封面图。这个IDL接口的目的是可以让客户端设备把一条新闻信息同步给服务端设备。

void tranShare(

        String deviceId,

        String shareUrl,

        String shareTitle,

        String shareAbstract,

        String shareImg)

我们再看一下根据这个IDL文件自动生成的proxy/stub文件代码,以proxy为例,我们可以看到它主要是把新闻各个信息字段通过data.write()函数序列化,然后把序列化的结果通过remote.sendRequest()方法发给服务端,服务端那边会通过stub文件接收这个对象,然后再把它反序列化,从而得到新闻各个信息字段。stub代码这里就不贴出来了。

package com.example.myapplication.manager;

import ohos.rpc.IRemoteObject;

import ohos.rpc.MessageOption;

import ohos.rpc.MessageParcel;

import ohos.rpc.RemoteException;

/**

 * News demo

 */

public class NewsDemoIDLProxy implements INewsDemoIDL {

    private static final String DESCRIPTOR = "com.example.myapplication.INewsDemoIDL";

    private static final int COMMAND_TRAN_SHARE = IRemoteObject.MIN_TRANSACTION_ID;

    private final IRemoteObject remote;

    NewsDemoIDLProxy(IRemoteObject remote) {

        this.remote = remote;

    }

    @Override

    public IRemoteObject asObject() {

        return remote;

    }

    @Override

    public void tranShare(

            String deviceId,

            String shareUrl,

            String shareTitle,

            String shareAbstract,

            String shareImg) throws RemoteException {

        MessageParcel data = MessageParcel.obtain();

        MessageParcel reply = MessageParcel.obtain();

        MessageOption option = new MessageOption(MessageOption.TF_SYNC);

        data.writeInterfaceToken(DESCRIPTOR);

        data.writeString(deviceId);

        data.writeString(shareUrl);

        data.writeString(shareTitle);

        data.writeString(shareAbstract);

        data.writeString(shareImg);

        try {

            remote.sendRequest(COMMAND_TRAN_SHARE, data, reply, option);

            reply.readException();

        } finally {

            data.reclaim();

            reply.reclaim();

        }

    }

}

定义好了代理和存根之后,客户端设备就可以通过代理连接服务端了。那么客户端又该如何发现和选中服务端设备呢?我们先运行一下demo看看界面,首页是一个新闻列表页,点击某条新闻后,是一个新闻详情页面,底部右侧角上有个分享按钮,点了后会弹出一个对话框(Harmony devices),这个对话框本意是要显示发现的其他鸿蒙设备,以便将新闻信息分布式的同步到那些设备上。

由于小编这里调试使用的是远程云手机,因此没有办法真正发现其他鸿蒙设备,如果是在家里用真正的手机调试,旁边又有其他鸿蒙设备比如电视的话,那这个对话框里就会显示鸿蒙设备列表的。

新闻列表界面

新闻详情页

点分享按钮弹出的对话框

那到底要怎么发现和连接分布式设备呢?在新闻详情页代码里(MainAbilityDetailSlice.java)里,我们可以看到分享按钮的响应事件处理代码,它调用了两个函数,一个用来获取分布式设备信息,一个用来展示设备列表。

iconShared.setClickedListener(listener -> {

    initDevices();

    showDeviceList();

});

再看看initDevices()是如何做的?通过鸿蒙系统提供的设备管理API DeviceManager直接可以获取分布式设备信息,这里返回的是一个List,因为可连接的分布式设备可能有多个。

private void initDevices() {

    if (devices.size() > 0) {

        devices.clear();

    }

    List<ohos.distributedschedule.interwork.DeviceInfo> deviceInfos =

            DeviceManager.getDeviceList(ohos.distributedschedule.interwork.DeviceInfo.FLAG_GET_ONLINE_DEVICE);

    LogUtil.info("MainAbilityDetailSlice", "deviceInfos size is :" + deviceInfos.size());

    devices.addAll(deviceInfos);

}

然后再把这些设备显示出来,让用户选择需要同步到哪个设备上去分布式运行?这里就比较简单了,把设备List绑定到一个对话框的列表UI里即可。

private void showDeviceList() {

    dialog = new CommonDialog(MainAbilityDetailSlice.this);

    dialog.setAutoClosable(true);

    dialog.setTitleText("Harmony devices");

    dialog.setSize(DIALOG_SIZE_WIDTH, DIALOG_SIZE_HEIGHT);

    ListContainer devicesListContainer = new ListContainer(getContext());

    DevicesListAdapter devicesListAdapter = new DevicesListAdapter(devices, this);

    devicesListContainer.setItemProvider(devicesListAdapter);

    devicesListContainer.setItemClickedListener((listContainer, component, position, listener) -> {

        dialog.destroy();

        startAbilityFA(devices.get(position).getDeviceId());

    });

    devicesListAdapter.notifyDataChanged();

    dialog.setContentCustomComponent(devicesListContainer);

    dialog.show();

}

仔细看看上面代码中,设备列表的点击事件listener,它调用了startAbilityFA()函数,意图在于当用户选择某个设备时,就开始分布式迁移到对应设备上去运行。打开它的代码,可以看到第一步是定义一个intent,里面填入目标设备deviceID,目标设备里要运行的ability(这个案例里是一个服务SharedService)。然后开始调用 connectAbility()函数连接远程设备,在连接成功的回调函数里,就可以拿到远端设备的代理,通过IDL接口就可以像操控本地设备一样,操控远端设备。至此,我们就完成了分布式开发啦。

private void startAbilityFA(String devicesId) {

    Intent intent = new Intent();

    Operation operation = new Intent.OperationBuilder()

            .withDeviceId(devicesId)

            .withBundleName(getBundleName())

            .withAbilityName("com.example.myapplication.SharedService")

            .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)

            .build();

    intent.setOperation(operation);

    boolean connectFlag = connectAbility(intent, new IAbilityConnection() {

        @Override

        public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int i) {

            INewsDemoIDL sharedManager = NewsDemoIDLStub.asInterface(iRemoteObject);

            try {

                sharedManager.tranShare(devicesId, "url", "title", "abstract", "image");

            } catch (RemoteException e) {

                LogUtil.info("MainAbilityDetailSlice", "connect successful,but have remote exception");

            }

        }

        @Override

        public void onAbilityDisconnectDone(ElementName elementName, int i) {

            disconnectAbility(this);

        }

    });

    if (connectFlag) {

        DialogUtil.toast(this, connectFlag ? "Sharing succeeded!"

                : "Sharing failed. Please try again later.", WAIT_TIME);

    }

}

作为Android开发者,看完鸿蒙核心优势分布式代码后,我们反过来从安卓里去找类似设计,可以看到与安卓Activity去Bind它的Services逻辑有点像,都是通过connect回调进行操作。

但安卓的bind机制只是为了完成跨进程通信,而鸿蒙的分布式机制是为了完成跨设备通信。这一点是鸿蒙胜于安卓之处,鸿蒙这样设计,会让所有的设备都能虚拟为一个大终端,每个设备都可以成为其他设备的一个组件,从而实现软件定义硬件。鸿蒙的核心优势现在你明白了吗?

作者:大岳岳

相关阅读:

中国芯片之父张汝京:创立世界第三大芯片生产厂,成功为华为“续命 ”

浅析鸿蒙系统 JavaScript GUI 技术栈

鸿蒙或成第五大操作系统,超越Linux

关于21CTO

21CTO.com是中国互联网第一技术社交与学习平台。为CTO、技术总监,技术专家,架构师、技术经理,高级研发工程师、PM等提供学习成长,教育培训,工作机会、人脉影响力等产品,同时为企业提供人才招聘,企业培训,软件研发等服务。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

热门产品

php编程基础教程.pptx|php编程培训,php,编程,基础,教程,pptx
php编程基础教程.pptx

历史上的今天:04月28日

referrer策略和meta标签的问题

referrer策略和meta标签的问题请求后端接口时,banner图片的请求出现403错误:GEThttp://xxxxxxxxxxxx403(Forbidden)。在网上搜寻一番,解决方法如下:在index.html中的head中添加&lt;meta name=&quot;referrer&quot; content=&quot;no-referrer&quot; /&gt;。在此之前,关于r

热门专题

安徽中源管业有限公司|安徽中源管业有限公司,安徽中源管业有限公司介绍,安徽中源管业有限公司电话,安徽中源管业有限公司地址,安徽中源管业有限公司厂家,安徽中源管业有限公司电力管,安徽中源管业有限公司管材
安徽中源管业有限公司
金诺幼儿园(春城路金诺幼儿园)|昆明官渡区幼儿园,幼儿园报名,官渡区幼儿园,春城路幼儿园,幼儿园招生,学前班,昆明幼儿园,金诺幼儿园,环城南路幼儿园,石井路幼儿园
金诺幼儿园(春城路金诺幼儿园)
大理科技管理学校|大理科技管理中等职业技术学校,大理市科技管理中等职业技术学校
大理科技管理学校
弥勒综合高中|弥勒综合高中
弥勒综合高中
综合高中|云南综合高中,昆明综合高中,综合高中能考本一吗,综合高中和普通高中的区别,综合高中是什么意思,综合高中能参加全国统一高考吗,综合高中可以考哪些大学,综合高中的学籍是什么
综合高中
云南综合高中|云南综合高中
云南综合高中
云南网站建设|云南网站制作,网站建设,云南网站开发,云南网站设计,云南网页设计,云南网站建设公司,云南网站建设
云南网站建设
安徽开放大学|安徽开放大学报名,安徽开放大学报考,安徽开放大学,什么是安徽开放大学,安徽开放大学学历,安徽开放大学学费,安徽开放大学报名条件,安徽开放大学报名时间,安徽开放大学学历,安徽开放大学专业
安徽开放大学

微信小程序

微信扫一扫体验

立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部