binder是什么?我们都在Activity通过getSystemService()方法获取系统的Service(例如:ActivityManagerService,WindowManagerService等),这些Activity一般都是客户端编写的,而系统的这些Service是属于服务端的。显然它们不会在同一进程(一般来说,一个APP单独在一个进程)。两个进程之间怎么通信?Binder就是两个进程通信的中间媒介。
知识储备在讲解Binder前,我们先了解一些Linux的基础知识
进程空间划分一个进程空间分为 用户空间 & 内核空间(Kernel),即把进程内 用户 & 内核 隔离开来进程间,内核空间的数据可共享,所以内核空间 = 可共享空间
所有进程共用1个内核空间
进程内 用户空间 & 内核空间 进行交互 需通过 系统调用,主要通过函数:
进程隔离 & 跨进程通信( IPC )copy_from_user():将用户空间的数据拷贝到内核空间copy_to_user():将内核空间的数据拷贝到用户空间
进程隔离
为了保证 安全性 & 独立性,一个进程 不能直接操作或者访问另一个进程,即Android的进程是相互独立、隔离的跨进程通信( IPC )
即进程间需进行数据交互、通信跨进程通信的基本原理
Binder 跨进程通信机制 模型 模型原理图a. 而Binder的作用则是:连接 两个进程,实现了mmap()系统调用,主要负责 创建数据接收的缓存空间 & 管理数据接收缓存Binder 跨进程通信机制 模型 基于 Client - Server 模式
b. 注:传统的跨进程通信需拷贝数据2次,但Binder机制只需1次,主要是使用到了内存映射,具体下面会详细说明
Binder 跨进程通信机制 模型 基于 Client - Server 模式
模型组成角色说明 跨进程通信的核心原理 模型原理步骤说明 项目实战 如何利用Binder实现进程间通信我们先看下Binder调用大致原理,这是Binder调用的标准调用过程,我们下面的代码将逐渐从不标准过程转成标准过程:
首先,我们 android studio 新建两个工程(两个 moudle 也可以,这里目的为创建两个运行在不同进程的app),一个Server,一个Client,而后,在Server中,我们新建一个java类Stub(类名无所谓),继承android.os.Binder,之后重写onTransact 方法,此处注意,onTransact方法的四个参数:
code:方法标识符,因为Client端对Server端的所有调用都会走到Server端的这个方法,所以理所应当Client端应该传递一个参数过来用以表示要调用哪个方法,注意这个int类型的标识必须介于 FIRST_CALL_TRANSACTION 和 LAST_CALL_TRANSACTION之间,所以我们给方法分配code的时候最好使用FIRST_CALL_TRANSACTION+n 这种方式data :Client传递过来的序列化数据包,Parcel类型reply: 如果Client端调用时需要返回值,Server通过这个对象将返回值传递回去,同样Parcel类型flag 用来区分这个调用是普通调用还是单边调用,普通调用时,Client端线程会阻塞,直到从Server端接收到返回值(所以如果Client端是主线程调用,其调用的Server端不宜做耗时操作,这会让造成Client的ANR),若flag==IBinder.FLAG_ONEWAY,则这次调用是单边调用,Client在传出数据后会立即执行下一段代码,此时两端异步执行,单边调用时函数返回值必须为void (也就是异步调用必须舍弃返回值,要返回值就必须阻塞等待)
有以上,Server端的功能就已经可以实现,但在两端通信时,为了两端Binder匹配,我们还需要在Server端做一次验证,用到data.enforceInterface(DEscriptOR)这个方法,DEscriptOR是Binder描述符,Binder Server和Client之间将通过这个描述符做验证,要想通过验证Binder通信的两端DEscriptOR必须相同,这也是为什么我们在使用AIDL帮助我们生成Binder代码的时候,必须把AIDL放在相同的包名下,因为SDK会根据包名为我们生成对应的DEscriptOR字符串,这里我们手写Binder,只需要保证两端相同就好了,包名字符串不是必须的
那么说了一堆的原理,我们来实践一下吧比如我们现在有这样一个需求
这个场景中解决的一个很常见的问题,就是我们的UI界面向service发送指令,完成界面响应对数据的控制功能
下面为Server端完整代码package com.zbc.androiddevelomentartdemo.service
import android.os.*
import com.ztsc.commonutils.logcat.Logger
import kotlin.jvm.Throws
//1. 创建服务端接口
interface IMessageServer : IInterface {
//定义要求子类实现的接口
@Throws(RemoteException::class)
fun registerService()
@Throws(RemoteException::class)
fun unRegisterService()
@Throws(RemoteException::class)
fun method1(message: String?)
@Throws(RemoteException::class)
fun method2(arg1: Int, arg2: Int): Int
@Throws(RemoteException::class)
fun sendMessage(message: String?)
@Throws(RemoteException::class)
fun registerNotifyBinder(binder: IBinder)
//3. 定义相关的传输协议
companion object {
const val DEscriptOR = "com.zbc.androidDevelopmentArtDemo.IMessageServer"
// 数据标识最好介于FIRST_CALL_TRANSACTION - LAST_CALL_TRANSACTION 之间
const val TRANSACTION_registerServiceNotify = Binder.FIRST_CALL_TRANSACTION + 1
const val TRANSACTION_unregisterServiceNotify = Binder.FIRST_CALL_TRANSACTION + 2
const val TRANSACTION_callServiceMethod = Binder.FIRST_CALL_TRANSACTION + 3
const val TRANSACTION_method_1 = Binder.FIRST_CALL_TRANSACTION + 4
const val TRANSACTION_method_2 = Binder.FIRST_CALL_TRANSACTION + 5
const val TRANSACTION_registerNotifyBinder = Binder.FIRST_CALL_TRANSACTION + 6
}
//2. 服务端创建Binder对象的实现类
abstract class Stub() : Binder(), IMessageServer {
init {
attachInterface(
this,
DEscriptOR
)
}
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
when (code) {
TRANSACTION_unregisterServiceNotify -> {
data.enforceInterface(DEscriptOR)
unRegisterService()
reply?.writeNoException()
reply?.writeString("服务端回复!n服务已结束!")
//成功处理相应后返回true
return true
}
TRANSACTION_callServiceMethod -> {
data.enforceInterface(DEscriptOR)
val data = data.readString()
Logger.e("---", "服务端接受到数据了! = $data")
reply?.writeNoException()
reply?.writeString("服务端回复!n老子接收到数据了! 收到的数据为 = $data")
//成功处理相应后返回true
return true
}
TRANSACTION_method_1 -> {
data.enforceInterface(DEscriptOR)
val data = data.readString()
method1(data)
reply?.writeNoException()
reply?.writeString("我是服务端,老子接收到了 数据为 = $data")
//成功处理相应后返回true
return true
}
TRANSACTION_method_2 -> {
data.enforceInterface(DEscriptOR)
//按写入的顺序读取数据
val result = method2(data.readInt(), data.readInt())
reply?.writeNoException()
reply?.writeString("我是服务端老子接收到了,计算了这两个目标数的乘积是 $result")
reply?.writeInt(result)
//成功处理相应后返回true
return true
}
TRANSACTION_registerNotifyBinder -> {
data.enforceInterface(DEscriptOR)
//按写入的顺序读取数据
registerNotifyBinder(data.readStrongBinder())
reply?.writeNoException()
reply?.writeString("notifyBinder注册成功!")
//成功处理相应后返回true
return true
}
}
return super.onTransact(code, data, reply, flags)
}
override fun isBinderAlive(): Boolean {
return super.isBinderAlive()
}
override fun asBinder(): IBinder {
return this
}
}
}
应用间要实现Binder通信必须要用Service来完成,想象客户端要怎样才能知道服务端的Binder地址并向其写入数据,一种是客户端通过一个Binder地址总管查询,通过键名查找到对应的Binder服务,这种方式就是有名Binder,这个总管类就是ServiceManager,应用进程获取系统服务就是通过查询这个Binder总管实现的,比如应用进程启动进入java层后就会去查找AMS的客户端,就是通过ServiceManager来查找的,但作为应用进程,是不能向ServiceManager注册有名Binder的,所以我们的客户端也没法通过ServiceManager查询到对应的Binder服务端,但应用进程间依然是可以获取到对方的Binder服务端的,Binder并不一定要注册到ServiceManager才能被获取到,这种Binder的获取方式就是通过已经获取到的Binder传递Binder,也就是说如果有某个有名Binder服务它提供了传递Binder的方法,那么我们就可以通过这个Binder服务来传递我们的匿名Binder,正好,AMS作为一个有名Binder提供了这个功能,其对Binder传递被封装到了Service组件当中,我们可以通过Service.onBind 来返回我们要传递的Binder客户端,而在Activity.bindService中获取到这个Binder:
class MessageServerService : Service() {
private var mClientBinder: IBinder? = null
private var mNotifyBinderProxy: NotifyBinderProxy? = null
// 4. 创建对应的Binder实例,Server端真正实现业务的方法
private val mBinder = object : IMessageServer.Stub() {
override fun registerService() {
}
override fun unRegisterService() {
this@MessageServerService.stopSelf()
}
override fun method1(message: String?) {
}
override fun method2(arg1: Int, arg2: Int): Int {
return arg1 * arg2
}
override fun sendMessage(message: String?) {
Logger.e("---", message ?: "")
}
override fun registerNotifyBinder(binder: IBinder) {
mClientBinder = binder
mNotifyBinderProxy = NotifyBinderProxy(mClientBinder)
}
}
override fun onDestroy() {
mClientBinder = null
super.onDestroy()
}
override fun onBind(intent: Intent): IBinder? {
// 4. 返回对象给客户端
return mBinder.asBinder()
}
}
AndroidManifest.xml中的代码
那么客户端是怎么回去这个Binder服务并传递数据的呢?
客户端实现想要获取服务端的binder,我们可以利用四大组件中service的bind() 函数完成和service的绑定,绑定完成后通过ServiceConnection回传对应的binder对象,之后我们可以通过这个binder对象完成向binder Server发送数据。
class PassingDataServiceActivity : AppCompatActivity() {
private var mIBinder: IBinder? = null
private var mIsConnectionBind = false
private var mBinderProxy: BinderProxy? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_passing_data_service)
connectService()
btn_act_send_data.setOnClickListener {
connectService()
mBinderProxy?.sendMessage("通过binder发送数据到另一个进程")
}
btn_act_call_method1.setOnClickListener {
connectService()
mBinderProxy?.method1("通过binder发送数据到另一个进程,调用约定好的method1")
}
btn_act_call_method2.setOnClickListener {
connectService()
mBinderProxy?.method2(10, 20)
}
}
private fun connectService() {
if (!mIsConnectionBind || mIBinder == null || !mIBinder!!.isBinderAlive) {
bindService()
}
}
private fun bindService() {
val intent = Intent(
this, MessageServerService::class.java
)
mIsConnectionBind = bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
service_message.text = "服务绑定成功!等待传输数据~"
}
private val mConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Logger.e("the ComponentName is :" + name?.className)
mIBinder = service
mBinderProxy = BinderProxy(mIBinder)
mBinderProxy?.registerNotifyBinder(mNotifyBinder)
liveData()
}
override fun onServiceDisconnected(name: ComponentName?) {
mIBinder = null
mIsConnectionBind = false
}
}
fun liveData() {
// Create the observer which updates the UI.
val nameObserver = Observer { newName ->
// Update the UI, in this case, a TextView.
service_message.text = newName
}
// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
mBinderProxy?.mCurrentName?.observe(this, nameObserver)
}
override fun onDestroy() {
super.onDestroy()
if (mIsConnectionBind) {
mBinderProxy?.unRegisterService()
mBinderProxy?.release()
mBinderProxy == null
unbindService(mConnection)
}
}
}
这里有一个小的技巧,我们不是通过IBinder 对象直接发送数据的,因为如果我们直接将代码放在Activity这个UI中就会出现通讯细节逻辑和UI界面出现耦合关系,这个在解耦思想中是不被允许的,那么怎么做呢?
这个行业中有特定的做法,是通过将binder的通讯的内部实现封装到一个BinderProxy的代理类中,完成代理的,这样你在回过头来,你现在再去理解上面我们的代码,是不是看这很简洁,和舒服呢!
BinderProxy类的内部实现package com.zbc.androiddevelomentartdemo.helper
import android.os.IBinder
import android.os.Parcel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.zbc.androiddevelomentartdemo.service.IMessageServer
import com.ztsc.commonutils.logcat.Logger
class BinderProxy(var mIBinder: IBinder?) : ViewModel() {
// Create a LiveData with a String
val mCurrentName: MutableLiveData by lazy {
MutableLiveData()
}
fun sendMessage(message: String?) {
if (!checkAvailable()) {
return
}
handle { data, reply ->
//因为是通过parcelable传递的数据,所以写入数据的顺序和大区数据的顺序一定要一致,任何信息,数量不一致和类型不一致都会error
data.writeInterfaceToken(IMessageServer.DEscriptOR)
data.writeString(message)
// https://www.jianshu.com/p/0fff33c09f34
mIBinder?.transact(IMessageServer.TRANSACTION_callServiceMethod, data, reply, 0)
//读取服务端的处理异常
reply.readException()
val result = reply.readString()
Logger.e("---", "接收到数据 = $result")
mCurrentName.value = "信息打印如下: n$result"
}
}
fun handle(block: (_data: Parcel, _reply: Parcel) -> Unit) {
try {
val data = Parcel.obtain()
val reply = Parcel.obtain()
try {
block(data, reply)
} catch (e: java.lang.Exception) {
Logger.e("sendMessageToService error!", e)
} finally {
data.recycle()
reply.recycle()
}
} catch (e: Exception) {
e.printStackTrace()
}
}
fun method1(message: String?) {
if (!checkAvailable()) {
return
}
handle { data, reply ->
//因为是通过parcelable传递的数据,所以写入数据的顺序和大区数据的顺序一定要一致,任何信息,数量不一致和类型不一致都会error
data.writeInterfaceToken(IMessageServer.DEscriptOR)
data.writeString(message)
// https://www.jianshu.com/p/0fff33c09f34
mIBinder?.transact(IMessageServer.TRANSACTION_method_1, data, reply, 0)
//读取服务端的处理异常
reply.readException()
val result = reply.readString()
mCurrentName.value = "信息打印如下: n$result"
Logger.e("---", "接收到数据 = $result")
}
}
fun method2(arg1: Int, arg2: Int): Int {
var result = 0
if (!checkAvailable()) {
return 0
}
handle { data, reply ->
//因为是通过parcelable传递的数据,所以写入数据的顺序和大区数据的顺序一定要一致,任何信息,数量不一致和类型不一致都会error
data.writeInterfaceToken(IMessageServer.DEscriptOR)
data.writeInt(arg1)
data.writeInt(arg2)
// https://www.jianshu.com/p/0fff33c09f34
mIBinder?.transact(IMessageServer.TRANSACTION_method_2, data, reply, 0)
//读取服务端的处理异常
reply.readException()
mCurrentName.value = "信息打印如下: n${reply.readString()}"
result = reply.readInt()
}
return result
}
fun registerNotifyBinder(binder:IBinder){
if (!checkAvailable()) {
return
}
handle { data, reply ->
//因为是通过parcelable传递的数据,所以写入数据的顺序和大区数据的顺序一定要一致,任何信息,数量不一致和类型不一致都会error
data.writeInterfaceToken(IMessageServer.DEscriptOR)
data.writeStrongBinder(binder)
// https://www.jianshu.com/p/0fff33c09f34
mIBinder?.transact(IMessageServer.TRANSACTION_registerNotifyBinder, data, reply, 0)
//读取服务端的处理异常
reply.readException()
val result = reply.readString()
mCurrentName.value = "信息打印如下: n$result"
Logger.e("---", "接收到数据 = $result")
}
}
fun unRegisterService(){
if (!checkAvailable()) {
return
}
handle { data, reply ->
//因为是通过parcelable传递的数据,所以写入数据的顺序和大区数据的顺序一定要一致,任何信息,数量不一致和类型不一致都会error
data.writeInterfaceToken(IMessageServer.DEscriptOR)
// https://www.jianshu.com/p/0fff33c09f34
mIBinder?.transact(IMessageServer.TRANSACTION_unregisterServiceNotify, data, reply, 0)
//读取服务端的处理异常
reply.readException()
val result = reply.readString()
mCurrentName.value = "信息打印如下: n$result"
Logger.e("---", "接收到数据 = $result")
}
}
fun release() {
mIBinder = null
}
private fun checkAvailable(): Boolean {
return mIBinder?.isBinderAlive ?: false
}
}
这个类的核心原理就是封装了binder通信调用的细节,而对调用方暴露的接口就类似于调用本地函数。下一步我们可以将Client端的接口和Server端的接口提取出一个公用的接口,让BinderProxy和Stub统一实现,这样就可以隐藏内部的实现细节,当我们提供给调用方的时候,开发人员就是感觉自己在调用本地的函数,完全不需要care内部负责的实现逻辑和底层原理。说到这个,大家可以详细的查看一个叫Messager的类,他的封装思想就是和这个完全一样的。
完成双向通讯通过上面的栗子,我们已经成功的完成,client向Server端发送信息了,那么我们怎么来完成Server主动的推送消息给Client端呢?实现类似于服务器向客户端完成消息推送的功能。
其实解决这个问题核心就是通过Client端已将获取的Server端的binder对象,将自己的binder对象传递给Server,Server端只要能够拿到这个Client端的Binder对象,不就可以完成消息的推送了么。
那么怎么实现binder的反向传递呢!有一个函数是关键
val data = Parcel.obtain() data.writeStrongBinder(binder)
完整的代码:
Client端传递自己的Binder给Server端BinderProxy.kt
fun registerNotifyBinder(binder:IBinder){
if (!checkAvailable()) {
return
}
handle { data, reply ->
//因为是通过parcelable传递的数据,所以写入数据的顺序和大区数据的顺序一定要一致,任何信息,数量不一致和类型不一致都会error
data.writeInterfaceToken(IMessageServer.DEscriptOR)
data.writeStrongBinder(binder)
// https://www.jianshu.com/p/0fff33c09f34
mIBinder?.transact(IMessageServer.TRANSACTION_registerNotifyBinder, data, reply, 0)
//读取服务端的处理异常
reply.readException()
val result = reply.readString()
mCurrentName.value = "信息打印如下: n$result"
Logger.e("---", "接收到数据 = $result")
}
}
Client 端的服务server实现
package com.zbc.androiddevelomentartdemo.service
import android.os.*
import kotlin.jvm.Throws
//1. 创建服务端接口
interface IServiceNotify : IInterface {
//定义要求子类实现的接口
@Throws(RemoteException::class)
fun registerService()
@Throws(RemoteException::class)
fun unRegisterService()
@Throws(RemoteException::class)
fun callServiceMethod()
@Throws(RemoteException::class)
fun sendMessage(message: String?)
//3. 定义相关的传输协议
companion object {
const val DEscriptOR = "com.zbc.androidDevelopmentArtDemo.IServiceNotify"
const val TRANSACTION_registerService = Binder.FIRST_CALL_TRANSACTION + 1
const val TRANSACTION_unRegisterService = Binder.FIRST_CALL_TRANSACTION + 2
const val TRANSACTION_callServiceMethod = Binder.FIRST_CALL_TRANSACTION + 3
const val TRANSACTION_sendMessage = Binder.FIRST_CALL_TRANSACTION + 4
}
//2. 服务端创建Binder对象的实现类
abstract class Proxy() : Binder(), IServiceNotify {
init {
attachInterface(
this,
DEscriptOR
)
}
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
when (code-) {
TRANSACTION_callServiceMethod -> {
data.enforceInterface(DEscriptOR)
callServiceMethod()
reply?.writeNoException()
reply?.writeString("客户端回复!ncallServiceMethod success!")
//成功处理相应后返回true
return true
}
TRANSACTION_sendMessage -> {
data.enforceInterface(DEscriptOR)
sendMessage(data.readString())
reply?.writeNoException()
reply?.writeString("客户端回复!n接收到服务端发送的数据!")
//成功处理相应后返回true
return true
}
}
return super.onTransact(code, data, reply, flags)
}
override fun isBinderAlive(): Boolean {
return super.isBinderAlive()
}
override fun asBinder(): IBinder {
return this
}
}
}
PassingDataServiceActivity.kt
package com.zbc.androiddevelomentartdemo.activity
class PassingDataServiceActivity : AppCompatActivity() {
private var mIBinder: IBinder? = null
private var mIsConnectionBind = false
private var mBinderProxy: BinderProxy? = null
//Client的binder服务对象
private val mNotifyBinder: IBinder by lazy {
object : IServiceNotify.Proxy() {
override fun registerService() {
}
override fun unRegisterService() {
}
override fun callServiceMethod() {
}
override fun sendMessage(message: String?) {
runOnUiThread{
service_message.text = "客户端服务接受到发送过来的数据 $message"
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_passing_data_service)
connectService()
btn_act_send_data.setOnClickListener {
connectService()
mBinderProxy?.sendMessage("通过binder发送数据到另一个进程")
}
btn_act_call_method1.setOnClickListener {
connectService()
mBinderProxy?.method1("通过binder发送数据到另一个进程,调用约定好的method1")
}
btn_act_call_method2.setOnClickListener {
connectService()
mBinderProxy?.method2(10, 20)
}
}
private fun connectService() {
if (!mIsConnectionBind || mIBinder == null || !mIBinder!!.isBinderAlive) {
bindService()
}
}
private fun bindService() {
val intent = Intent(
this, MessageServerService::class.java
)
intent.putExtras(Bundle()
.apply {
putParcelable(
"systemMsgBean",
SystemMsgBean(
"a00001",
"Hello ! 我是通过bundle传递数据",
System.currentTimeMillis(),
0
)
)
})
mIsConnectionBind = bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
service_message.text = "服务绑定成功!等待传输数据~"
}
private val mConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Logger.e("the ComponentName is :" + name?.className)
mIBinder = service
mBinderProxy = BinderProxy(mIBinder)
mBinderProxy?.registerNotifyBinder(mNotifyBinder)
liveData()
}
override fun onServiceDisconnected(name: ComponentName?) {
mIBinder = null
mIsConnectionBind = false
}
}
fun liveData() {
// Create the observer which updates the UI.
val nameObserver = Observer { newName ->
// Update the UI, in this case, a TextView.
service_message.text = newName
}
// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
mBinderProxy?.mCurrentName?.observe(this, nameObserver)
}
override fun onDestroy() {
super.onDestroy()
if (mIsConnectionBind) {
mBinderProxy?.unRegisterService()
mBinderProxy?.release()
mBinderProxy == null
unbindService(mConnection)
}
}
}
上面的代码是实例化这个客户端的Binder Server,并传递给了服务端。
那么服务端的真正实现是什么样的呢?
Server端注册自己的binder包装类
NotifyBinderProxy.kt是包装类,放在服务端使用
package com.zbc.androiddevelomentartdemo.helper
import android.os.IBinder
import android.os.Parcel
import com.zbc.androiddevelomentartdemo.service.IServiceNotify
import com.ztsc.commonutils.logcat.Logger
class NotifyBinderProxy(var mIBinder: IBinder?) : IServiceNotify {
override fun registerService() {
}
override fun unRegisterService() {
}
override fun callServiceMethod() {
}
fun handle(block: (_data: Parcel, _reply: Parcel) -> Unit) {
try {
val data = Parcel.obtain()
val reply = Parcel.obtain()
try {
block(data, reply)
} catch (e: java.lang.Exception) {
Logger.e("sendMessageToService error!", e)
} finally {
data.recycle()
reply.recycle()
}
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun sendMessage(message: String?) {
if (!checkAvailable()) {
return
}
handle { data, reply ->
//因为是通过parcelable传递的数据,所以写入数据的顺序和大区数据的顺序一定要一致,任何信息,数量不一致和类型不一致都会error
data.writeInterfaceToken(IServiceNotify.DEscriptOR)
data.writeString(message)
// https://www.jianshu.com/p/0fff33c09f34
mIBinder?.transact(IServiceNotify.TRANSACTION_sendMessage, data, reply, 0)
//读取服务端的处理异常
reply.readException()
val result = reply.readString()
Logger.e("---", "接收到数据 = $result")
}
}
override fun asBinder(): IBinder {
return mIBinder!!
}
private fun checkAvailable(): Boolean {
return mIBinder?.isBinderAlive ?: false
}
}
服务端发送数据
class MessageServerService : Service() {
private var mClientBinder: IBinder? = null
private var mNotifyBinderProxy: NotifyBinderProxy? = null
......
override fun onBind(intent: Intent): IBinder? {
val bundle: Bundle = intent.extras as Bundle
val systemMsgBean: SystemMsgBean? = bundle.getParcelable("systemMsgBean") as SystemMsgBean?
Logger.e("onBind 接收到的消息为————————n" + systemMsgBean?.toString() ?: "")
GlobalScope.launch(Dispatchers.IO) {
do {
//模拟服务端推送消息给客户端
delay(3000)
mNotifyBinderProxy?.sendMessage("来自服务的的数据推送")
Logger.e("send message!" )
} while (mClientBinder != null)
}
// 4. 返回对象给客户端
return mBinder.asBinder()
}
}
到这里,一个完整的Service跨进程,双向通讯的实现就完成了。怎么样很简单吧,反正你记住这个模型到时候自己套用就可以了。
如何通过上面的模型传递大文件那当然是通过内存共享机制了,不过中间需要借助与binder传递对应的共享文件操作符信息
核心类MemoryFileHelper.kt
package com.zbc.androiddevelomentartdemo.helper
import android.os.*
import android.util.Log
import com.zbc.androiddevelomentartdemo.content.ContentValue
import java.io.FileDescriptor
import java.io.FileInputStream
import java.io.IOException
class MemoryFileHelper {
companion object {
private const val TAG = "MemoryFileHelper"
fun writeToMemory(data: ByteArray?, length: Int): ParcelFileDescriptor? {
var parcelFileDescriptor: ParcelFileDescriptor? = null
var memoryFile: MemoryFile? = null
try {
memoryFile = MemoryFile("", length)
memoryFile.writeBytes(data, 0, 0, length)
val method = MemoryFile::class.java.getDeclaredMethod("getFileDescriptor")
method.isAccessible = true
val fileDescriptor = method.invoke(memoryFile) as FileDescriptor
parcelFileDescriptor = ParcelFileDescriptor.dup(fileDescriptor)
} catch (ex: Exception) {
Log.w(TAG, "catch write to memory error", ex)
} finally {
memoryFile?.close()
}
return parcelFileDescriptor
}
fun sendToFdServer(
binder: IBinder?,
KEY_FD: String,
data: ByteArray?,
length: Int,
width: Int,
height: Int, block: (binder: IBinder?, bundle: Bundle) -> Unit
) {
val parcelFileDescriptor: ParcelFileDescriptor =
writeToMemory(data, length) ?: throw Exception("writeToMemory error!")
val params = java.util.HashMap(1)
params[KEY_FD] = parcelFileDescriptor
val bundle = Bundle()
bundle.putSerializable(
KEY_FD,
params
)
bundle.putInt(ContentValue.KEY_LENGTH, length)
bundle.putInt(ContentValue.KEY_WIDTH, width)
bundle.putInt(ContentValue.KEY_HEIGHT, height)
block(binder, bundle)
}
fun readFromMemoryAsByteArray(
KEY_FD: String,
params: HashMap,
length: Int
): ByteArray? {
val fileDescriptor = params[KEY_FD]
fileDescriptor?.apply {
val data = ByteArray(length)
var fileInputStream: FileInputStream? = null
try {
fileInputStream = FileInputStream(fileDescriptor.fileDescriptor)
fileInputStream.read(data)
return data
} catch (e: java.lang.Exception) {
Log.w(TAG, "catch read from memory error", e)
} finally {
fileInputStream?.apply {
try {
fileDescriptor.close()
} catch (e: IOException) {
Log.w(TAG, "catch close fd error", e)
}
}
}
}
return null
}
}
}
binder 传递这个操作符的关键代码如下
class NotifyBinderProxy(var mIBinder: IBinder?) : IServiceNotify {
...
fun handle(block: (_data: Parcel, _reply: Parcel) -> Unit) {
try {
val data = Parcel.obtain()
val reply = Parcel.obtain()
try {
block(data, reply)
} catch (e: java.lang.Exception) {
Logger.e("sendMessageToService error!", e)
} finally {
data.recycle()
reply.recycle()
}
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun sendMessage(message: String?) {
if (!checkAvailable()) {
return
}
handle { data, reply ->
//因为是通过parcelable传递的数据,所以写入数据的顺序和大区数据的顺序一定要一致,任何信息,数量不一致和类型不一致都会error
data.writeInterfaceToken(IServiceNotify.DEscriptOR)
data.writeString(message)
// https://www.jianshu.com/p/0fff33c09f34
mIBinder?.transact(IServiceNotify.TRANSACTION_sendMessage, data, reply, 0)
//读取服务端的处理异常
reply.readException()
val result = reply.readString()
Logger.e("---", "接收到数据 = $result")
}
}
override fun transmitMemoryFile(byteArray: ByteArray?) {
if (!checkAvailable()) {
return
}
MemoryFileHelper.sendToFdServer(
mIBinder,
ContentValue.KEY_FD,
byteArray,
byteArray?.size ?: 0,
0,
0
) { _, bundle ->
handle { data, reply ->
//因为是通过parcelable传递的数据,所以写入数据的顺序和大区数据的顺序一定要一致,任何信息,数量不一致和类型不一致都会error
data.writeInterfaceToken(IServiceNotify.DEscriptOR)
data.writeBundle(bundle)
// https://www.jianshu.com/p/0fff33c09f34
mIBinder?.transact(IServiceNotify.TRANSACTION_transmitMemoryFile, data, reply, 0)
//读取服务端的处理异常
reply.readException()
Logger.e("信息打印如下: n${reply.readString()}")
}
}
}
override fun asBinder(): IBinder {
return mIBinder!!
}
private fun checkAvailable(): Boolean {
return mIBinder?.isBinderAlive ?: false
}
}
当然你会问,如果我仅仅期望可以单项的向Service发送控制命令,这个怎么实现呢!使用binder这种形式是不是太过于复杂了。
简易方案,通过Messenger与Message实现binder通信如果我们自信的查看源码,你就会发现,Messenger其实就是帮助我们封装了底层的Binder服务实现,我们可以基于这个封装完成简单的IPC通讯
Messenger.java
public final class Messenger implements Parcelable {
private final IMessenger mTarget;
}
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
其中的IMessager是一个AIDL
看完Message的源码,你或许就会恍然大悟了,这不就是完全复制的我们的BInder的那套东西么。
代码实战依旧是这个小栗子
废话不多说直接上代码。
UI界面端package com.zbc.androiddevelomentartdemo.activity
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.*
import androidx.appcompat.app.AppCompatActivity
import com.zbc.androiddevelomentartdemo.R
import com.zbc.androiddevelomentartdemo.entity.SystemMsgBean
import com.zbc.androiddevelomentartdemo.entity.UserBean
import com.zbc.androiddevelomentartdemo.service.RemoteServerService
import com.ztsc.commonutils.logcat.Logger
import kotlinx.android.synthetic.main.activity_transform_data_to_service.*
class TransformDataServiceActivity : AppCompatActivity() {
companion object {
private const val CODE_base = 0
const val CODE_REPLAY = CODE_base + 1
}
private var isBindServiceSuccess = false
private var mServiceMessenger: Messenger? = null
private val mHandler =
object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
when (msg.what) {
CODE_REPLAY -> {
service_message.text ="${msg.data?.getString("message")}"
}
}
}
}
private val mMessager = Messenger(mHandler)
private val mServiceConnection by lazy {
object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
mServiceMessenger = Messenger(service)
service_message.text = "服务绑定成功!"
}
override fun onServiceDisconnected(name: ComponentName?) {
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_transform_data_to_service)
bindService(
Intent().apply {
setAction("service.RemoteServerService")
setPackage(this@TransformDataServiceActivity.packageName)
},
mServiceConnection,
Context.BIND_AUTO_CREATE
)
btn_act_send_data.setOnClickListener {
val mess = Message.obtain()
mServiceMessenger?.send(mess.apply {
what = RemoteServerService.CODE_BINDER_REGISTER
data = Bundle().apply {
putString("data","注册binder")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
putBinder("binder", mMessager.binder)
}
}
replyTo = mMessager
})
mess.recycle()
}
}
override fun onDestroy() {
super.onDestroy()
if (isBindServiceSuccess) {
mServiceMessenger = null
}
}
}
remote Server端
package com.zbc.androiddevelomentartdemo.service
import android.app.Service
import android.content.Intent
import android.os.*
import com.zbc.androiddevelomentartdemo.activity.TransformDataServiceActivity
import com.ztsc.commonutils.logcat.Logger
class RemoteServerService : Service() {
companion object {
private const val CODE_base = 0
const val CODE_BINDER_REGISTER = CODE_base + 1
const val CODE_CALL_METHOD = CODE_base + 2
}
private var mNotifyMessenger: Messenger? = null
private val mHandler by lazy {
object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
when (msg.what) {
CODE_BINDER_REGISTER -> {
val reply = Message.obtain()
msg.data?.apply {
//如果本次通讯是跨进程的数据传递,一定要设置classLoader,否则会因找不到可用的classLoader而报错 Parcel: Class not found when unmarshalling: com.zbc.androiddevelomentartdemo.entity.SystemMsgBean
classLoader = javaClass.classLoader
get("binder")?.apply {
mNotifyMessenger = Messenger(this as IBinder)
}
Logger.e("Service接收到信息!${getString("data")}")
}
msg.replyTo.send(reply.apply {
what = TransformDataServiceActivity.CODE_REPLAY
data = Bundle().apply { putString("message", "binder服务双向注册成功!") }
//请不要向obj中存放数据,或crash 无法序列化
//obj ="xxxx"
})
reply.recycle()
}
}
}
}
}
val mMessager = Messenger(mHandler)
override fun onBind(intent: Intent?): IBinder? {
return mMessager.binder
}
override fun onDestroy() {
super.onDestroy()
mHandler.removeCallbacksAndMessages(null)
}
}
注意:
Message中请不要将数据存放在obj中,会因为底层无法控制序列化顺序导致报错Messenger底层也是通过AIDL完成的,只不过代理成了Messager最终对用户的数据暴露为我们Handler、和Message的形式。
通过Message传递Bundle对象的时候,如果是IPC通讯,需要指定Bundle的ClassLoader
//如果本次通讯是跨进程的数据传递,一定要设置classLoader,否则会因找不到可用的classLoader而报错 Parcel: Class not found when unmarshalling: com.zbc.androiddevelomentartdemo.entity.SystemMsgBean classLoader = javaClass.classLoader完整的demo演示下载链接:
https://github.com/benchegnzhou/AndroidDevelomentArtDemo
文档参考:https://www.jianshu.com/p/0fff33c09f34
https://www.jianshu.com/p/f9a8f1747358



