项目场景:
两个APP使用AIDL跨进程IPC通讯。A为服务端APP,B为客户端APP。
问题描述
现象:A自动升级版本后,无法向客户端B通讯,会打印log“AIDL未连接客户端”,但B可以向A通讯。
实现代码:
class Service{private val mArtAppStub by lazy { newIArtApp() }private val mListeners = RemoteCallbackList<IListenerInterface>()private val mLock = ReentrantLock()/*** 实例化代理*/private fun newIArtApp() = object : IServiceInterface.Stub() {override fun registerListener(listener: IListenerInterface?) {LogUtils.e(mTag, "registerListener:$listener")mListeners.register(listener)}}// ..... 省略若干sendCallback调用代码/*** 发送回调客户端事件* @param sendEvent 发送事件* @param unexe 未执行*/private fun sendCallback(unexe: () -> Unit = {}, sendEvent: (IListenerInterface) -> Unit) {mLock.lock()try {val length = mListeners.beginBroadcast()if(length == 0){LogUtils.e(mTag,"AIDL未连接客户端,请等待连接。。。")unexe()}else{// 只向最后一个监听器通讯sendEvent(mListeners.getBroadcastItem(length - 1))}} catch (e: Throwable) {e.printStackTrace()} finally {mListeners.finishBroadcast()mLock.unlock()}}
}
原因分析:
在A升级后, B自动重新建立aidl连接,并通讯:
以下为服务端log
启动服务init
启动服务onCreate
回复客户端 数据 ...
启动服务init
启动服务onCreate
可以看到这里service被启动了两次,如果多次升级,也相应增加启动次数,这样会导致内部变量mListeners也被实例化了多次,里面存储的客户端listener也不在了,所以回调客户端时 找不到任何的listener。
解决方案:
我们可以将mListeners提取为APP生命周期的全局变量,作为共享数据;这样无论service重复创建多少次都不会受影响,同时也可以正常通讯;
修改后的代码如下:
class Service{companion object{/** 回调客户端的监听 */private val mListeners = RemoteCallbackList<IListenerInterface>()}// 将此处移至伴随对象内。// private val mListeners = RemoteCallbackList<IListenerInterface>()
}