当前位置:   article > 正文

鸿蒙HarmonyOS学习笔记之Service Ability实现跨端通信_鸿蒙无用户交互

鸿蒙无用户交互

一、基本概念

基于Service模板的Ability(以下简称“Service”)主要用于后台运行任务(如执行音乐播放、文件下载等),但不提供用户交互界面。Service可由其他应用或Ability启动,即使用户切换到其他应用,Service仍将在后台继续运行。

Service是单实例的。在一个设备上,相同的Service只会存在一个实例。如果多个Ability共用这个实例,只有当与Service绑定的所有Ability都退出后,Service才能够退出。由于Service是在主线程里执行的,因此,如果在Service里面的操作时间过长,开发者必须在Service里创建新的线程来处理,防止造成主线程阻塞,应用程序无响应。更多内容可以参考官方文档

二、使用

1.创建Service

新建ServiceAbility 继承Ability

public class ServiceAbility extends Ability {
    private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "Demo");

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

    @Override
    public void onBackground() {
        super.onBackground();
        HiLog.info(LABEL_LOG, "ServiceAbility::onBackground");
    }

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

    @Override
    public void onCommand(Intent intent, boolean restart, int startId) {
    }

    @Override
    public IRemoteObject onConnect(Intent intent) {
        HiLog.info(LABEL_LOG,"ServiceAbility::onConnect");
        return new GameRemoteObject("GameRemoteObject").asObject();
    }

    @Override
    public void onDisconnect(Intent intent) {
    }


    /**
     * 用于接受跨端信息
     *
     */
    private static class GameRemoteObject extends RemoteObject implements IRemoteBroker{

        public GameRemoteObject(String descriptor) {
            super(descriptor);
        }

        @Override
        public IRemoteObject asObject() {
            return this;
        }

        public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option){
            //接受跨端信息
            String message =data.readString();

            //通过 ConnectionHelper 将消息回调给 PageAbility
            ConnectionHelper.getInstance().sendMessage(message);

            //回传结果给消息发送者
            reply.writeInt(Constants.ERR_OK);
            return true;
        }
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

同时在config.json文件中需要注册
在这里插入图片描述

2.创建ConnectionHelper

public class ConnectionHelper {

    /**
     * 私有构造方法,避免单例被额外实例化
     */
    private ConnectionHelper(){}


    /**
     * 静态内部类,持有唯一的 ConnectionHelper 实例
     */
    private static class ConnectionHelperHolder{
        private static final ConnectionHelper INSTANCE =new ConnectionHelper();
    }


    ![/**
     * 对外提供获取实例的方法
     *](https://img-blog.csdnimg.cn/c13fc3bfef3c4c1ba23a60ed3308f532.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6YaJ5oSP5Li25Y2D5bGC5qKm,size_20,color_FFFFFF,t_70,g_se,x_16)

     * @return ConnectionHelper 实例
     */
    public static ConnectionHelper getInstance(){
        return ConnectionHelperHolder.INSTANCE;
    }

    /**
     * 通信回调
     */
    private IConnectionCallback mConnectionCallback;

    /**
     * 设置通信回调
     *
     * @param connectionCallback 通信回调
     */
    public void setCallback(IConnectionCallback connectionCallback){
        this.mConnectionCallback=connectionCallback;
    }


    /**
     * 发消息
     *
     * @param message 消息
     */
    public void sendMessage(String message){
        if(mConnectionCallback!=null){
            mConnectionCallback.onCallback(message);
        }
    }

    public interface IConnectionCallback {

        /**
         * 通信回调
         *
         * @param message 消息
         */
        void onCallback(String message);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

3.创建RemoteProxy

public class RemoteProxy implements IRemoteBroker {

    private static final HiLogLabel LABEL_LOG = new HiLogLabel(0,0x01008,"RemoteProxy");

    private final IRemoteObject remote;

    /**
     * 构造方法
     *
     * @param remote IRemoteObject实例
     */
    public RemoteProxy(IRemoteObject remote) {
        this.remote = remote;
    }

    @Override
    public IRemoteObject asObject() {
        return remote;
    }


    public void sendMessage(String message){
        //把消息封装到MessageParcel
        MessageParcel data= MessageParcel.obtain();
        data.writeString(message);

        MessageParcel reply =MessageParcel.obtain();
        MessageOption option =new MessageOption(MessageOption.TF_SYNC);
        try {
            //通过RemoteObject实例发送消息
            remote.sendRequest(IRemoteObject.MIN_TRANSACTION_ID,data,reply,option);

            //获取消息传递结果
            int ec=reply.readInt();
            if(ec!= Constants.ERR_OK){
                throw new RemoteException();
            }
        } catch (RemoteException e) {
            HiLog.error(LABEL_LOG,"RemoteException: %{public}s",e.getMessage());
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

4.启动service

这里不需要启动setvice,直接连接即可
启动本地设备Service的代码示例如下:


Intent intent = new Intent();
Operation operation = new Intent.OperationBuilder()
        .withDeviceId("")
        .withBundleName("com.domainname.hiworld.himusic")
        .withAbilityName("com.domainname.hiworld.himusic.ServiceAbility")
        .build();
intent.setOperation(operation);
startAbility(intent);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

启动远程设备Service的代码示例如下:

Intent intent = new Intent();
Operation operation = new Intent.OperationBuilder()
        .withDeviceId("deviceId")
        .withBundleName("com.domainname.hiworld.himusic")
        .withAbilityName("com.domainname.hiworld.himusic.ServiceAbility")
        .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE) // 设置支持分布式调度系统多设备启动的标识
        .build();
intent.setOperation(operation);
startAbility(intent);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

5.连接Service

定义相关变量

private Text countdownText;

private static RemoteProxy mRemoteProxy=null;

private final IAbilityConnection connection=new IAbilityConnection() {
        @Override
        public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int i) {
            //连接成功,实例化代理
            mRemoteProxy=new RemoteProxy(iRemoteObject);
            getUITaskDispatcher().asyncDispatch(()->{
                countdownText.setText("已连接");

            });
        }

        @Override
        public void onAbilityDisconnectDone(ElementName elementName, int i) {

        }
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

连接函数

private void connectService(String deviceId){
        Intent intent=new Intent();
        Operation operation=new Intent.OperationBuilder()
                .withDeviceId(deviceId)
                .withBundleName(getBundleName())
                .withAbilityName(ServiceAbility.class.getName())
                .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
                .build();
        intent.setOperation(operation);

        connectAbility(intent,connection);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

发送消息函数

private void sendMessage(String message){
        if(mRemoteProxy==null){
            ToastUtils.show(getContext(),"无跨端连接代理");
        }
        else{
            mRemoteProxy.sendMessage(message);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

消息处理函数

private void handleMessage(String message){
        //对接收到的消息进行处理
    }
  • 1
  • 2
  • 3

最终效果,当正常连接后会出现已连接字样
在这里插入图片描述

三、注意

为了可以正确使得主机端和远程端连接成功,主机端主动连接远程端,远程端主动连接主机端。在onStart函数里面应该去获取主机端和远程端的设备ID


isMainDevice=intent.getBooleanParam(Constants.PARAM_KEY_IS_MAIN_DEVICE,true);  
mRemoteDeviceId=intent.getStringParam(Constants.PARAM_KEY_REMOTE_DEVICE_ID);
mMainDeviceId=intent.getStringParam(Constants.PARAM_KEY_MAIN_DEVICE_ID);
  • 1
  • 2
  • 3
  • 4

同时判断当前页面是以主机还是远程端的形式创建,并在onActive函数根据是否为主机去使用不同的连接参数

if(isMainDevice){
    connectService(mRemoteDeviceId);
}
else {
    connectService(mMainDeviceId);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

四、参考

鸿蒙官方开发文档
鸿蒙官方示例代码

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/338194
推荐阅读
相关标签
  

闽ICP备14008679号