Android-Service端和Clinet端通讯-如果client被杀了

  最近做了一个android的语音项目,service端集成了语音服务,该service提供相关的语音SDK,比如语音搜索音乐,然后音乐app service集成这个SDK,从而获得语音能力。

在实际开发的过程中遇到两个棘手的问题:

1 Voice Service起来了,如果Music并没有启动,有人请求语音搜索音乐,那么怎么能告诉你呢?

2 如果Music起来并且通过bind接口绑定了Voice,那么voice如何知道呢?

针对两个问题我们进行分析:

1 Voice Service起来而Music没有起来,如果有人请求语音搜索音乐,触发了相关的回调

onSeachMusic(MusicBean musicBean)

这个时候怎么发给music呢?

答案其实不难,就是如果music service没有启动,则它也不会利用service提供的aidl向voice service注册语音监听服务,这个时候只要判断这个就可以解决,然后还有一个问题,就是把准备触发的音乐搜索的回调(AIDL中提供给Music的)给保存起来,等到我启动了music service让他向我注册,再发送给他。

这里有一个技巧,为了实现所有方法的统一管理,我这里使用动态代理,去缓存即将要发送的任意一个client的回调的方法和参数。

public boolean onSearchMusic(MusicModel model)
    {
        DataCenter.getInstance().recordVoiceRequest(DataCenter.IntentDomain.MUSIC);
        IMusicControlCb  callback = (IMusicControlCb) RegisterAIDLManager
                .getInstance()
                .getInterface(ServiceManager.MUSIC_KEY);
        boolean ret = false;
        try {
            if (callback != null && callback.asBinder().pingBinder()) {
                ret = callback.searchMusic(model);//触发音乐的搜索回调监听
            } else {
                ret = CallbackProxyManager.getInstance().getMusicCallbackProxy().searchMusic(model);//代理
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return ret;
    }

这里有个难点就是AIDL文件如何使用Android的动态代理呢?Interface我们知道可以,但是aidl文件并不知道,废话不多说直接上代码,这里用到了反射

private void initAudioBookCallbackProxy() {
        Class<?> reflectCallback = null;
       //核心部分
        try {
            reflectCallback =  Class.forName("com.byton.vas.vassdk.IOnlineFMControlCb");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        mAudioBookCallbackProxyHandler = new CallbackProxyHandler(ServiceManager.AUDIO_BOOK_KEY);
        mAudioBookCallbackProxy = (IOnlineFMControlCb) Proxy.newProxyInstance(
                CallbackProxyManager.class.getClassLoader(), new Class[] { reflectCallback },//核心
                mAudioBookCallbackProxyHandler);
    }

这里一旦完成,就可以利用动态代理对任意的aidl回调方法和参数进行缓存,然后去启动相关的client应用服务。

 public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        boolean result = ServiceManager.getInstance().startRemoteService(key);
        if (result) {
            InvokeObject invokeObject = new InvokeObject();
            invokeObject.setKey(key);
            invokeObject.setMethod(method);
            invokeObject.setObjects(objects);
            CallbackEventsCache.getInstance().product(invokeObject);
            return true;
        }
       return false;
    }

一旦music的应用启动了和我们绑定了,则这个时候必然向我们注册,我们只要在注册的地方,将所有即将发送给这个应用的缓存指令发送给他就可以了。

 public void registerMusicControlCb(IMusicControlCb callback) {
        RegisterAIDLManager.getInstance().addInterface(ServiceManager.MUSIC_KEY, callback);
        CallbackEventsCache.getInstance().consume();
    }

总结一下就是如下几点:

  • 判断你是否活着
  • 如果没有活?则利用动态代理以及BlockingQuee构建消费者-生产者队列缓存所有的语音aidl回调方法和参数
  • 启动相应的client端回调,向voice注册。
  • 触发缓存中的回调方法。

第二个问题,如果client端music service被杀了,那么我的语音指令怎么办。

有人可能会说,它不是和你bind了吗?它死了voice service的unbind回调肯定能知道。对不起错了,如果有N个client bind servcie,除非所有的client都断开了,你的service才会收到unbind回调。

这里有个方法就是

callback.asBinder().pingBinder()

这个AIDL的方法,可以用来判断目标client是否和你还在绑定的状态。一旦语音回调触发,只要判断这个就可以知道client是否活着,如果没有,则可以按照第一个问题的解决方案进行处理。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值