android binder入门-手动实现
最近在学习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
客户端module
具体的实现过程代码如下:
```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自定义相机Camera实现手动对焦的方法示例
-
Android通过继承Binder类实现多进程通信
-
Android自定义相机Camera实现手动对焦的方法示例
-
Android入门之ActivityGroup+GridView实现Tab分页标签的方法
-
Android利用Binder实现进程通信
-
android开发中手动v2签名实现方法
-
Android通过继承Binder类实现多进程通信
-
Android 入门第九讲02-视频(本地视频播放,暂停,获取播放时间,重新播放,播放到指定位置,MediaController类(实现进度条,快进,播放暂停),播放网络视频)
-
Android studio 入门实战——注册登录+验证功能的实现
-
Android Binder入门学习笔记