Android进程间binder通信和回调

前言

因为业务需要,需要实现两个app相互通信传递数据的功能,并可以回调

实现

准备:客户端的首先创建两个Android项目,一个项目为服务端,另外一个为客户端。服务端的applicationId(即包名)为com.project.service,客户端的applicationId(即包名)为com.project.client。

服务端

1.在app(应用)模块的build.gradle文件中进行aidl的配置

......
android {
   ......
    sourceSets {
        main {
            aidl.srcDirs = ['src/main/aidl']
        }
    }
    buildFeatures {
        aidl true
    }
   ......
}
......

2.在app/src/main创建aidl目录,然后创建com/project/service/test目录。后面的aidl文件都在该目录路径里面

3.创建IStudentManagerService.aidl文件,该文件编译后自动会在app/build/generated/aidl_source_output_dir/debug/out/com/project/service/test中生成继承Binder类的Sub抽象类。

// IStudentManagerService.aidl
package com.project.service.test;
import java.util.List;
import com.project.service.test.Student;
import com.project.service.test.StudentCallBack;
// Declare any non-default types here with import statements

interface IStudentManagerService {
     //aidl中定义的方法传入的数据和返回数据的基本数据类型, 这个方法可删可不删,没有啥重要的
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
    List<Student> getStudents();
    int addStudent(in Student student);
    int getStudentNumbers(int type);
    void addStudentCallback(StudentCallBack studentCallback);
    void removeStudentCallback(StudentCallBack studentCallback);
}

4.创建Student.aidl文件

// Student.aidl
package com.project.service.test;

parcelable Student;

5.创建StudentCallBack.aidl,用于后面服务端回调客户端

// StudentCallBack.aidl
package com.project.service.test;
import com.project.service.test.Student;
// Declare any non-default types here with import statements

interface StudentCallBack {
    void selectPerfectStudentNow(in Student student,int stuNo);
}

6.在app/src/main/java/com/project/service/test目录下创建Student.kt,注意,Student.kt的目录路径(com/project/service/test)要和Student.aidl一样

package com.project.service.test

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

/**
 *
 * @ProjectName:    Test
 * @Package:        com.project.service.service
 * @ClassName:      Student
 * @Description:
 * @Author:         gzl
 * @CreateDate:     2023/10/17 11:45
 */
class Student() : Parcelable {
    var stuNo: String? = null
    var name: String? = null
    var age: Int? = null

    constructor(parcel: Parcel) : this() {
        age = parcel.readInt()
        stuNo = parcel.readString()
        name = parcel.readString()
    }

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeInt(age ?: 0)
        parcel.writeString(stuNo ?: "")
        parcel.writeString(name ?: "")
    }

    override fun describeContents(): Int {
        return 0
    }

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

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

    override fun toString(): String {
        return "age $age  \n name $name  \n  stuNo $stuNo  \n"
    }

}

7.在app/src/main/java/com/project/service目录或其他子目录下创建StudentManagerService.kt

package com.project.service

import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.os.RemoteCallbackList
import android.os.RemoteException
import android.util.Log
import com.project.service.test.IStudentManagerService
import com.project.service.test.Student
import com.project.service.test.StudentCallBack



class StudentManagerService : Service() {
    val TAG = "StudentManagerService"
    val remoteCallbackList = RemoteCallbackList<StudentCallBack>()
    override fun onCreate() {
        super.onCreate()
        Log.d(TAG, "onCreate ")
    }

    private val binder = object : IStudentManagerService.Stub() {
        override fun basicTypes(
            anInt: Int,
            aLong: Long,
            aBoolean: Boolean,
            aFloat: Float,
            aDouble: Double,
            aString: String?
        ) {
        }

        override fun getStudents(): List<Student> {
            return listOf(Student().apply {
                stuNo = "8"
                name = "zss"
                age = 9
            })
        }

        override fun addStudent(student: Student?): Int {
            Log.d(TAG, "addStudent ${student?.toString()} ")
            student?.let { onAddStudentCallback(it) }
            return 1
        }

        override fun getStudentNumbers(type: Int): Int {
            Log.d(TAG, "getStudentNumbers $type ")
            return 2
        }

        override fun addStudentCallback(studentCallback: StudentCallBack?) {
            Log.d(TAG, "addStudentCallback  ")
            studentCallback?.let { remoteCallbackList.register(studentCallback) }
        }

        override fun removeStudentCallback(studentCallback: StudentCallBack?) {
            Log.d(TAG, "removeStudentCallback  ")
            studentCallback?.let { remoteCallbackList.unregister(it) }
        }

    }

    private fun onAddStudentCallback(student: Student) {
        val callBackNum = remoteCallbackList.beginBroadcast()
        for (i in 0 until callBackNum) {
            try {
                remoteCallbackList.getBroadcastItem(i).selectPerfectStudentNow(student, 3)
            } catch (e: RemoteException) {
                e.printStackTrace()
            }
        }
        remoteCallbackList.finishBroadcast()
    }

    override fun onBind(intent: Intent?): IBinder {
        return binder
    }
}

8.在AndroidManifest.xml中注册服务

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
        android:icon="@mipmap/ic_launcher"
        android:label="service">
        ......
        <service
            android:name="com.project.service.StudentManagerService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.project.service.StudentManagerService" />
            </intent-filter>
        </service>
        ......
    </application>

</manifest>
客户端

1.在app(应用)模块的build.gradle文件中进行aidl的配置

......
android {
   ......
    sourceSets {
        main {
            aidl.srcDirs = ['src/main/aidl']
        }
    }
    buildFeatures {
        aidl true
    }
   ......
}
......

2.将服务端app/src/main/aidl整个目录包含(IStudentManagerService.aidl,Student.aidl,StudentCallBack.aidl)文件复制到客户端app/src/main目录中,注意目录结构与文件名必须和服务端保持一致,每个aidl文件里面的方法顺序也不能改变。

3.将服务端app/src/main/java/com/project/service/test/Student.kt文件复制到客户端app/src/main/java/com/project/service/test/目录中,注意目录结构与文件名,方法等必须和服务端保持一致

4.在activity中先绑定服务,然后调用服务端提供的方法addStudentCallback,把回调注入到服务端中,当调用addStudent之后,会回调StudentCallBack的方法。

package com.project.client.test

import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.clickable
import androidx.compose.material3.Text
import androidx.compose.ui.Modifier
import com.project.service.test.IStudentManagerService
import com.project.service.test.Student
import com.project.service.test.StudentCallBack

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Text("Hello world!", modifier = Modifier.clickable {
                startCallServiceMethod()
            })
        }
        bindService()
    }


    var iStudentService: IStudentManagerService? = null

    private fun bindService() {
        val intent = Intent()
        intent.action = "com.project.service.StudentManagerService"
        intent.setPackage("com.project.service")
        intent.setClassName(
            "com.project.service",
            "com.project.service.StudentManagerService"
        )
        try {
            bindService(intent, object : ServiceConnection {
                override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) {
                    Log.e("bindService", "onServiceConnected")
                    iStudentService = IStudentManagerService.Stub.asInterface(iBinder)
                }

                override fun onServiceDisconnected(componentName: ComponentName) {
                    iStudentService = null
                    Log.e("bindService", "onServiceDisconnected")
                }
            }, Context.BIND_AUTO_CREATE)
        } catch (e: Exception) {
            Log.e("bindService", e.message ?: "")
        }
    }

    private fun startCallServiceMethod() {
        iStudentService?.apply {
            addStudentCallback(object : StudentCallBack.Stub() {

                override fun selectPerfectStudentNow(student: Student?, stuNo: Int) {
                    Log.d("bindService", "selectPerfectStudentNow ${student?.toString()}")
                }
            })
        }
        iStudentService?.addStudent(Student().apply {
            age = 78
            name = "dpdpdp"
            stuNo = "bbbbbbbb"
        })
    }
}

5.在AndroidManifest.xml中申请服务端app的包的访问,注意这边的action一定要和服务端注册服务时的intent-filter的action保持一致,代码中的action也是一致的

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <queries>
        <package android:name="com.project.service" />
        <intent>
            <action android:name="com.project.service.StudentManagerService" />
        </intent>
    </queries>
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="client"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Test">
     ......
    </application>

</manifest>

注意:xml的package,setPackage等这些包名是app的applicationId.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值