欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android binder入门-手动实现

程序员文章站 2022-04-13 11:30:39
...

最近在学习binder原理,先从手动实现binder通信开始学习
代码实现参考:https://www.jianshu.com/p/37368fab05bf

几个概念:

Person
实体类,要序列化,否则传递数据过程中会异常
PersonManager
接口,需要继承IInterface,才能具备进程间通信的能力
内部提供具体的客户端操作方法
PersonManagerProxy
PersonManager方法实现类,实现具体的方法操作,具体的操作需要通过binder.transat实现
PersonManagerStub
1、继承Binder,实现PersonManager
2、继承Binder可以跨进程传输数据
3、实现PersonManager,可以远程操作服务端数据
4、构造方法调用this.attachInterface(this, DESCRIPTOR);作用就是向BinderService注册Binder服务。只有注册了binder,客户端才能查询到binder对象,并且使用内部必须有静态方法 asInterface(binder:IBinder),才能方便将binder对象转换成PersonManager,才能调用服务端定义好的方法。
5、onTransat:PersonManagerProxy类中调用的方法就是在方法内部进行实际处理,并通过跨进程传输到远程service

PersonManagerService
远程service,客户端调用过后才是绑定成功,并建立连接内部有PersonManagerStub对象,并实现了具体的数据操作,是数据操作的最后一步,也是可以和服务端主页面进行实际页面操作
还需要在manifest中进行注册,设置可以跨进程访问,设置intent-filter的action

其实可以理解为客户端启动服务,获取服务端的binder对象PersonManager,但是获取的时候,要先检查之前是否有对象,所以就通过PersonManagerStub检查一下,如果存在就返回之前的使用对象,不存在就返回PersonManager的实现代理类PersonManagerProxy。其他就是binder注册进入ServiceManager的内容了,固定写法。

服务端要实现上面的几个类Person、PersonManager、PersonManagerProxy、PersonManagerStub、PersonManagerService
客户端中,要将服务端的Person、PersonManager、PersonManagerProxy、PersonManagerStub拷贝过去,并且包名还要和服务端的一致

代码结构:
服务端module
android binder入门-手动实现

客户端module
android binder入门-手动实现

具体的实现过程代码如下:


```java
package com.example.binderserver.server

import android.os.Parcel
import android.os.Parcelable

class Person():Parcelable {
    var name:String?=null
    constructor(parcel: Parcel) : this() {
        name = parcel.readString()
    }

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(name)
    }

    override fun describeContents(): Int {
        return 0
    }

    override fun toString(): String {
        return "PErson(name=$name)"
    }

    override fun equals(other: Any?): Boolean {
        if (this == other) return true
        if (javaClass!=other?.javaClass)
            return false
        other as Person
        if (name!=other.name){
            return false
        }
        return true
    }

    companion object CREATOR : Parcelable.Creator<Person> {
        override fun createFromParcel(parcel: Parcel): Person {
            return Person(parcel)
        }

        override fun newArray(size: Int): Array<Person?> {
            return arrayOfNulls(size)
        }
    }

}
interface PersonManager : IInterface{

    @Throws(RemoteException::class)
    fun addPerson(person: Person)
    
    @Throws(RemoteException::class)
    fun deletePerson(person: Person)
    
    @Throws(RemoteException::class)
    fun getPersons():List<Person>
}
package com.example.binderserver.server

import android.os.IBinder
import android.os.Parcel

class PersonManagerProxy:PersonManager {
    /**
     * 远程binder对象
     */
    var remote:IBinder?=null
    private companion object var DESCRIPTOR:String="com.example.binderserver.server.PersonManager"

    constructor(remote:IBinder){
        this.remote = remote
    }

    fun getInterfaceDescriptor():String{
        return DESCRIPTOR
    }



    override fun addPerson(person: Person) {
        var data = Parcel.obtain()
        var replay = Parcel.obtain()

        try {
            data.writeInterfaceToken(DESCRIPTOR)
            if (person != null) {
                data.writeInt(1)
                person.writeToParcel(data, 0)
            }else{
                data.writeInt(0)
            }
            remote?.transact(PersonManagerStub.TRANSAVTION_addperson,data,replay,0)
            replay.readException()
        }finally {
            data.recycle()
            replay.recycle()
        }
    }

    override fun deletePerson(person: Person) {
        var data = Parcel.obtain()
        var replay = Parcel.obtain()

        try {
            data.writeInterfaceToken(DESCRIPTOR)
            if (person != null) {
                data.writeInt(1)
                person.writeToParcel(data, 0)
            }else{
                data.writeInt(0)
            }
            remote?.transact(PersonManagerStub.TRANSAVTION_deleteperson,data,replay,0)
            replay.readException()
        }finally {
            data.recycle()
            replay.recycle()
        }
    }

    override fun getPersons(): List<Person> {
        var data = Parcel.obtain()
        var replay = Parcel.obtain()
        var result:ArrayList<Person>

        try {
            data.writeInterfaceToken(DESCRIPTOR)
            remote?.transact(PersonManagerStub.TRANSAVTION_getpersons,data,replay,0)
            replay.readException()
            result = replay.createTypedArrayList(Person.CREATOR)!!
        }finally {
            data.recycle()
            replay.recycle()
        }
        return result
    }

    override fun asBinder(): IBinder {
       return remote!!
    }
}
package com.example.binderserver.server

import android.os.Binder
import android.os.IBinder
import android.os.Parcel

abstract class PersonManagerStub:Binder,PersonManager {

    constructor(){
        this.attachInterface(this,DESCRIPTOR)
    }

    companion object {
        var DESCRIPTOR:String="com.example.binderserver.server.PersonManager"
        var TRANSAVTION_getpersons = IBinder.FIRST_CALL_TRANSACTION
        var TRANSAVTION_addperson = IBinder.FIRST_CALL_TRANSACTION+1
        var TRANSAVTION_deleteperson = IBinder.FIRST_CALL_TRANSACTION+2

        fun asInterface(binder: IBinder):PersonManager{
            var iin = binder.queryLocalInterface(DESCRIPTOR)
            if (iin is PersonManager){
                return iin
            }
            return PersonManagerProxy(binder)
        }
    }

    override fun asBinder(): IBinder {
        return this
    }

    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
        when(code){
            INTERFACE_TRANSACTION->{
                reply?.writeString(DESCRIPTOR)
                return true
            }
            TRANSAVTION_getpersons->{
                data.enforceInterface(DESCRIPTOR)
                var result = this.getPersons()
                reply?.writeNoException()
                reply?.writeTypedList(result)
                return true
            }
            TRANSAVTION_addperson->{
                data.enforceInterface(DESCRIPTOR)
                var arg0:Person?=null
                if (data.readInt()!=0){
                    arg0 = Person.CREATOR.createFromParcel(data)
                }
                this.addPerson(person = arg0!!)
                reply?.writeNoException()
                return true

            }
            TRANSAVTION_deleteperson->{
                data.enforceInterface(DESCRIPTOR)
                var person:Person?=null
                if (data.readInt()!=0){
                    person = Person.CREATOR.createFromParcel(data)
                }
                this.deletePerson(person!!)
                reply?.writeNoException()
                return true
            }
        }

        return super.onTransact(code, data, reply, flags)
    }

}
package com.example.binderserver

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.util.Log
import android.view.LayoutInflater.from
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.example.binderserver.server.Person
import com.example.binderserver.server.PersonManagerStub
import java.util.Date.from

/**
 * 远程service
 */
class PersonManagerService :Service() {
    private var persons:ArrayList<Person> = ArrayList()
    var CHANNEL_ID = "personmanager"
    var notificationId = 1

    override fun onCreate() {
        super.onCreate()
        Log.e("binder service","onCreate")
        createNotificationChannel()
        showNotification()
    }

    /**
     * 将当前人数显示通过通知栏显示出来
     */
    private fun showNotification() {
        var builder = NotificationCompat.Builder(this,CHANNEL_ID)
                .setContentTitle("0fdg")
                .setStyle(NotificationCompat.BigTextStyle().bigText("当前人数是${persons.size},人员信息是:${persons.toString()}"))
                .setSmallIcon(R.mipmap.ic_launcher)
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        with(NotificationManagerCompat.from(this)){
            startForeground(notificationId,builder.build())
        }
    }

    /**
     * 首先创建通知渠道,在进行通知显示
     */
    private fun createNotificationChannel() {
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
            val name = getString(R.string.channel_name)
            val descriptionText = getString(R.string.channel_description)
            val importance = NotificationManager.IMPORTANCE_DEFAULT
            val channel = NotificationChannel(CHANNEL_ID,name,importance).apply {
                description = descriptionText
            }
            val notificationManager:NotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)

        }
    }

    override fun onBind(intent: Intent?): IBinder? {
        Log.e("binder service","onBind")
        return binder
    }

    private val binder = object :PersonManagerStub(){
        override fun addPerson(person: com.example.binderserver.server.Person) {
            persons.add(person)
            Log.e("binder service","addPerson")
            showNotification()
        }

        override fun deletePerson(person: com.example.binderserver.server.Person) {
            persons.remove(person)
            Log.e("binder service","deletePerson")
            showNotification()
        }

        override fun getPersons(): List<com.example.binderserver.server.Person> {
           Log.e("binder service","getPersons")
            return persons
        }

    }
}

manifest中进行注册:

<service android:name=".PersonManagerService"
    android:exported="true"
    android:enabled="true">
    <intent-filter>
        <action android:name="com.example.bindserver.aidlservice"/>
    </intent-filter>
</service>

客户端的activity代码

class BinderClientActivity : AppCompatActivity() {
    private var mService:PersonManager?=null
    private var isBound = false

    private val mConnection = object :ServiceConnection{
        override fun onServiceConnected(name: ComponentName?, service: IBinder) {
            Log.e("binder client","连接成功")
            mService = PersonManagerStub.asInterface(service)
            isBound = true
        }

        override fun onServiceDisconnected(name: ComponentName?) {
            Log.e("binder client","onServiceDisconnected")
            mService = null
            isBound = false
        }

    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_binder_client)
        addListener()
    }

    override fun onDestroy() {
        super.onDestroy()
        if (isBound){
            unbindService(mConnection)
        }
    }

    private fun addListener() {
        findViewById<TextView>(R.id.tv_bind_service).setOnClickListener {
            Toast.makeText(this,"绑定服务",Toast.LENGTH_SHORT).show()
            var intent = Intent()
            intent.`package` = "com.example.binderserver"
            intent.action = "com.example.bindserver.aidlservice"
            bindService(intent,mConnection,Context.BIND_AUTO_CREATE)
        }

        findViewById<TextView>(R.id.tv_add).setOnClickListener {
            Log.e("binder client","addPerson")
            var person = Person()
            person.name = "张三"
            mService?.addPerson(person)
        }

        findViewById<TextView>(R.id.tv_delete).setOnClickListener {
            Log.e("binder client","deletePerson")
            var person = Person()
            person.name = "张三"
            mService?.deletePerson(person)
        }

        findViewById<TextView>(R.id.tv_get_persons).setOnClickListener {
            Log.e("binder client","getPersons")
            mService?.getPersons()
        }

    }
}

布局代码:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".BinderClientActivity">

    <TextView
        android:id="@+id/tv_bind_service"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="bind_service person"
        android:layout_marginTop="20dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv_add"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="add person"
        android:layout_marginTop="20dp"
        app:layout_constraintTop_toBottomOf="@id/tv_bind_service"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        />

    <TextView
        android:id="@+id/tv_delete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="delete person"
        android:layout_marginTop="20dp"
        app:layout_constraintTop_toBottomOf="@id/tv_add"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        />

    <TextView
        android:id="@+id/tv_get_persons"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="getpersons person"
        android:layout_marginTop="20dp"
        app:layout_constraintTop_toBottomOf="@id/tv_delete"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
         />

</androidx.constraintlayout.widget.ConstraintLayout>

代码写好之后,先安装服务端,然后在安装客户端,客户端就可以绑定服务端,然后进行数据操作

相关标签: android binder