背景
在公司实习的过程中需要用到跨进程的通信,查看项目之前的代码发现是通过aidl绑定的两个进程,但是因为两个进程需要互相收发消息,所以A→B, B←A进行了两次绑定。本着能只绑定一次就不多浪费一次的原则,选择对这个通信方式进行改造。
首先aidl这个东西就不再多赘述,是非常基础的多进程通信方法。
其次通过一次aidl绑定后就可以调用Server端的服务,这一点也不多赘述,因为是aidl的平A用法。
这里主要说明一下如何使用aidl实现反向调用客户端的方法
用法
通过查找其他博主的文章,发现统一使用了RemoteCallbackList<?>() 这种列表,通过客户端将callback注册到这个列表中,在服务端遍历这个列表,便可以调用里面存储的客户端的方法。
下面是具体做法:
-
首先书写两个aidl文件,作为服务端和客户端双方希望对方调用的接口:
package com.example.crossprocesslistenertest;
import com.example.crossprocesslistenertest.Anotherlistener;
interface Myinterface {
void doService(int id, out Bundle params);
void registerListener(Anotherlistener listener);
void unregisterListener(Anotherlistener listener);
}
package com.example.crossprocesslistenertest;
interface Anotherlistener {
void doListener1(int id, inout Bundle params);
}
别忘了build一下,否则接口文件不会生成
-
创建一个Service,作为被绑定的服务端(别忘了在AndroidMaifest中把这个Service注册在另一个进程)
class AnotherService : Service() {
private val TAG = "remote process"
private val mListener = RemoteCallbackList<Anotherlistener>()
private val service = object : Myinterface.Stub(){
override fun doService(id : Int, params : Bundle) {
Log.d(TAG,"the remote service was did")
}
override fun registerListener(listener: Anotherlistener?) {
mListener.register(listener)
}
override fun unregisterListener(listener: Anotherlistener?) {
mListener.unregister(listener)
}
}
fun doMainListener(){
val n =mListener.beginBroadcast()
Log.d("AnotherService","${mListener.registeredCallbackCount}")
for (i in 0 until n){
mListener.getBroadcastItem(i).doListener1()
}
mListener.finishBroadcast()
}
override fun onBind(intent: Intent): IBinder? {
return service.asBinder
}
}
-
接下来在主进程中的MainActivity中书写逻辑: class MainActivity : AppCompatActivity() {
private var mService : Myinterface? = null
private val TAG = "main process"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
bind()
do_service.setOnClickListener {
mService?.doService(3, Bundle().apply {
putString("key","11111")
})
}
}
private val listener = object : Anotherlistener.Stub(){
override fun doListener1(id : Int, params : Bundle) {
Log.d(TAG, "the main process listener1111 was called")
}
}
private val connection = object : ServiceConnection{
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
mService = Myinterface.Stub.asInterface(service)
mService?.registerListener(listener)
Log.d(TAG, "Connection success!")
}
override fun onServiceDisconnected(name: ComponentName?) {
mService = null
}
}
private fun bind(){
bindService(Intent(this, AnotherService::class.java).setType("MAIN"), connection, BIND_AUTO_CREATE)
}
private fun unbind(){
if(mService?.asBinder()?.isBinderAlive == true){
mService?.unregisterListener(listener)
unbindService(connection)
}
}
override fun onDestroy() {
if (mService?.asBinder()?.isBinderAlive == true){
mService?.unregisterListener(listener)
}
unbindService(connection)
super.onDestroy()
}
}
-
尝试一下客户端使用Web端的服务:(每次点击按钮都会打印) ![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RZRTtv9X-1627653981041)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/defd5b4f-02da-4ed6-bc16-893bbf85be38/Untitled.png)]](https://img-blog.csdnimg.cn/7dc9e1b5022a48c9b4edd85a39d20759.png) -
目前服务端是一个Service,没有View,只能添加一个线程帮我们去触发这个操作:
override fun onCreate() {
super.onCreate()
Thread(doSth).start()
}
private val doSth = Runnable {
for (i in 1 .. 10){
Thread.sleep(1000)
doMainListener()
}
}
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N5lEA6DX-1627653981042)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/7f9d9b76-c848-44ad-8552-ef8895b3655e/Untitled.png)]](https://img-blog.csdnimg.cn/3ba3855fa65a4c4fb6350dca01d3baed.png) 以上省略6次
以上实现了AIDL中Server端回调Client端的方法,但是如果每次调用callback的时候,都需要对RemoteCallbackList 进行开启→遍历→关闭,是不是有点费事?如果我们的的回调接口中有很多个方法,而这些方法在服务端被异步调用,就会存在RemoteCallbackList的开启问题,因为RemoteCallbackList的所有方法是被Synchronize修饰的,那么异步调用就会被强制变成同步过程,降低了效率。
那么为了解决上述的问题,在下一篇文章中会尝试将RemoteCallbackList中的回调方法取出,并直接使用
|