栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Binder机制

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Binder机制

Binder机制 Binder是什么

binder是什么?我们都在Activity通过getSystemService()方法获取系统的Service(例如:ActivityManagerService,WindowManagerService等),这些Activity一般都是客户端编写的,而系统的这些Service是属于服务端的。显然它们不会在同一进程(一般来说,一个APP单独在一个进程)。两个进程之间怎么通信?Binder就是两个进程通信的中间媒介。

知识储备

在讲解Binder前,我们先了解一些Linux的基础知识

进程空间划分

一个进程空间分为 用户空间 & 内核空间(Kernel),即把进程内 用户 & 内核 隔离开来进程间,内核空间的数据可共享,所以内核空间 = 可共享空间

所有进程共用1个内核空间

进程内 用户空间 & 内核空间 进行交互 需通过 系统调用,主要通过函数:

    copy_from_user():将用户空间的数据拷贝到内核空间copy_to_user():将内核空间的数据拷贝到用户空间

进程隔离 & 跨进程通信( IPC )

进程隔离
为了保证 安全性 & 独立性,一个进程 不能直接操作或者访问另一个进程,即Android的进程是相互独立、隔离的跨进程通信( IPC )
即进程间需进行数据交互、通信跨进程通信的基本原理

a. 而Binder的作用则是:连接 两个进程,实现了mmap()系统调用,主要负责 创建数据接收的缓存空间 & 管理数据接收缓存Binder 跨进程通信机制 模型 基于 Client - Server 模式
b. 注:传统的跨进程通信需拷贝数据2次,但Binder机制只需1次,主要是使用到了内存映射,具体下面会详细说明

Binder 跨进程通信机制 模型 模型原理图

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)
    }
}
注意:

Messenger底层也是通过AIDL完成的,只不过代理成了Messager最终对用户的数据暴露为我们Handler、和Message的形式。

Message中请不要将数据存放在obj中,会因为底层无法控制序列化顺序导致报错

通过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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/720867.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号