文明网i中国精神文明建设门户网站,百度云如何做网站,康定网站建设公司,杭州网站推广排名Binder 进程通信基础使用 一、服务端进程创建 Service#xff0c;Service 中创建 Binder 子类对象并于 onBind 中返回。xml 定义。
创建 Service#xff0c;创建 Binder 子类对象并于 onBind 返回
class UserService : Service() {private companion object {const val TAG… Binder 进程通信基础使用
一、服务端进程创建 ServiceService 中创建 Binder 子类对象并于 onBind 中返回。xml 定义。
创建 Service创建 Binder 子类对象并于 onBind 返回
class UserService : Service() {private companion object {const val TAG: String test_service_tag}private val service object : Binder() {override fun onTransact(p0: Int, p1: Parcel, p2: Parcel?, p3: Int): Boolean {p1.enforceInterface(UserService)when(p0) {0 - {// 读取客户端传递的 int 值val readInt p1.readInt()Log.e(TAG, service get int : $readInt)// 写入无异常表示这次调用没有出现问题p2?.writeNoException()p2?.writeInt(readInt * 2)return true}1 - {// 读取客户端传递的 String 值val readString p1.readString()Log.e(TAG, service get String: $readString)// 写入无异常表示这次调用没有出现问题p2?.writeNoException()p2?.writeString(service version: 1.0.0)return true}// 2的时候传的 Binder拿到客户端 Binder 模拟跨进程回调也就是此时随时可以双向通信2 - {// 读取客户端传递的 Binder 对象双向通信直接点说就是callback回调对象val readStrongBinder p1.readStrongBinder()Log.e(TAG, service get binder: $readStrongBinder execute method:)val data Parcel.obtain()val reply Parcel.obtain()try {//确认 token 令牌data.writeInterfaceToken(UserService)data.writeInt(111)// 回调客户端保存传来 Binder 后随时可以回调这里简易写一下就行readStrongBinder.transact(0 ,data, reply, 0)//这个方法必须要 reply 调了writeException 或 writeNoException不然直接抛异常看方法源码就看出来了reply.readException()Log.e(TAG, service binder call back result: reply.readInt())} finally {data.recycle()reply.recycle()}return true}else - {Log.d(TAG, service unspecific value)}}return super.onTransact(p0, p1, p2, p3)}}override fun onBind(p0: Intent?): IBinder {Log.e(TAG, service onBind Service )return service}
}简易说明onTransact(p0: Int, p1: Parcel, p2: Parcel?, p3: Int) 在客户端调用传过去的 Binder.transact 方法时会回调此方法 p0: requestCode 请求码可以用于区分不同的执行操作类似 aidl 中不同的方法的区分 p1: data 数据客户端传来的数据客户端 write 写入服务端 read 读取。 p2: reply 数据当 p3 参数是 0时在服务端进行 write客户端调完方法直接 read 读取写入的值。 p3: flag 标记0 表示这个方法有返回值可对 reply 进行写入然后客户端读取1 的话表示单向数据只从客户端到服务端没有返回值就算对 reply 写值客户端也读不到。
在服务端 AndroidManifest.xml 里定义 service. service android:name.UserService android:exportedtrueandroid:enabledtrueandroid:permissioncom.example.serviceintent-filteraction android:namecom.example.service.UserService //intent-filter/service简易说明exported 外部调用开关permission 权限限制不设置不一定能绑定上
二、客户端绑定服务通过返回的 Binder 执行逻辑传递 Binder 完成跨进程回调。xml 权限及包名定义。
客户端 AndroidManifest.xml 中设定权限、包名. permission android:namecom.example.service /uses-permission android:namecom.example.service /queriespackage android:namecom.example.service //queries简易说明TargetSDK 30之后绑定非自身应用的 service 要加里面写绑定服务的包名. : 在服务端对 service 要求需要该权限所以要加。
客户端绑定服务。 private var service: IBinder? null//这个代码是定义的 class成员变量比较懒就仍这儿了// 绑定服务不能只要 action会抛异常看了下实现最少得加个包名val intent Intent(com.example.service.UserService).also {it.component ComponentName(com.example.service, com.example.service.UserService)}Log.e(TAG, activity bind service result bindService(intent, object : ServiceConnection {override fun onServiceConnected(name: ComponentName?, service: IBinder?) {Log.e(TAG, activity onServiceConnected, service : $service)// 保存服务端传递的 Binder就是这个thisMainActivity.service service}override fun onServiceDisconnected(name: ComponentName?) {Log.e(TAG, activity onServiceDisconnected, service : $service)thisMainActivity.service null}// 最后一个参数要传 Context.BIND_AUTO_CREATE不然有问题啥问题可以看 ComtextImpl.bindService 的源码里面有 flags 参数校验}, Context.BIND_AUTO_CREATE))简易说明就俩注意点 1intent 不止传 actionclass 和 component 还得加上这两个其中的一个. 2binderService 最后一个参数 flag 需要传 Context.BIND_AUTO_CREATE.
调用 transact 完成跨进程通信。 private fun getServiceInfo() {Log.d(TAG, activity getServiceInfo, service : $service)val data0 Parcel.obtain()val reply0 Parcel.obtain()val requestCode0 0try {//写入 token 令牌这里是因为客户端写了验证 token服务端没写就可以不加data0.writeInterfaceToken(UserService)data0.writeInt(100)service?.transact(requestCode0, data0, reply0, 0)//这个方法必须要 reply 调了writeException 或 writeNoException不然直接抛异常看方法源码就看出来了reply0.readException()Log.e(TAG,activity requestCode : $requestCode0, getServiceInfo : reply0.readInt())} finally {data0.recycle()reply0.recycle()}val data1 Parcel.obtain()val reply1 Parcel.obtain()val requestCode1 1try {data1.writeInterfaceToken(UserService)data1.writeString(what is service version?)service?.transact(requestCode1, data1, reply1, 0)reply1.readException()Log.e(TAG,activity requestCode : $requestCode1, getServiceInfo : reply1.readString())} finally {data1.recycle()reply1.recycle()}}问题点 1token 验证。当服务端进行 data.enforceInterface(令牌值) token验证时调用的客户端必须写入 token data.writeInterfaceToken(令牌值) 2默认就有异常。客户端调完 transact() 后如果调了 reply.readException() 那客户端必须要调用 reply.writeNoException() 或者 reply.writeException()。 3data(p1) 和 reply(p2)。data 是客户端写值服务端读取相当于 aidl 方法入参reply 服务端写入客户端读取相当于 aidl 方法返回值。 4回调双向通信。客户端服务端在已连接情况下双方随时可向对方通信客户端调用的 transact() 中data(p1) 写入的时候写入 Binder 对象服务端拿到 Binder 对象后保存这样双方都保存了对方的 Binder也就是随时可以通信。直接点说就是常见的 registerCallback 方式客户端拿着 service服务端拿着 callback。
三、记一下。。
Binder 子类对象完成跨进程调用Binder.transact(p0,p1,p2,p3) 调用时回调 Binder.onTransact(p0,p1,p2,p3)p0 code 区分此次事件该做啥p1 是传来的参数可以读取另一边的数据p2 是传给对方的数据写入p3 0时 p2有效1时p2无效.Parcel token 验证。transact(p0,p1,p2,p3) 调用方调用前写入onTransact(p0,p1,p2,p3) 接收方中验证。Parcel.exception 。transact(p0,p1,p2,p3) 调用方调用后读取onTransact(p0,p1,p2,p3) 接收方执行时写入。