当前位置: 代码迷 >> 综合 >> Android的IPC机制(中)—— Kotlin 详细实现 AIDL
  详细解决方案

Android的IPC机制(中)—— Kotlin 详细实现 AIDL

热度:48   发布时间:2023-12-06 11:02:31.0

Android的IPC机制


Android的IPC机制上篇:简单介绍了Bundle、文件共享、Messenger的简单实现
中篇将详细介绍如何用 Kotlin 实现 Android 的 AIDL
下篇将简单介绍 ContentProviderSocket


??IPC(Inter-ProcessCommunication),含义为进程间通信跨进程通信,是指两个不同进程之间进行数据交换的过程。

??任何操作系统都有其相应的IPC机制,例如:Windows 上可以通过剪贴板、管道和邮槽等来进行进程间通信。Linux 上可以通过命名管道、共享内存、信号量等来进行进程间通信。Android 是一种基于 Linux 内核的移动操作系统,对于 Android 来说,它也有其特有的进程间通信方式。


??

四、AIDL

??AIDL(Android Interface definition language),意为 Android 接口定义语言。我们可以利用 AIDL 定义客户端与服务端均认可的编程接口,以便二者在不同进程间进行通信。在 Android 中,一个进程通常无法访问另一个进程的内存。因此,为了进行通信,进程需将其对象分解成可供操作系统理解的原语,并将其编组为可供您操作的对象。Android 使用 AIDL 来处理,避免了编写执行该编组操作代码的繁琐操作。

??AIDL 接口的调用是直接函数调用。实际情况的差异取决于调用是来自本地进程中的线程,还是远程进程中的线程。

1、AIDL支持的数据类型:

  • 基本数据类型(int、long、char、boolean、double)

  • String 和 CharSequence

  • List : 只支持 ArrrayList ,且每个元素都必须是 AIDL 支持的元素

  • Map :只支持 HashMap,且每个元素都必须是 AIDL 支持的元素

  • Parcelable :所有实现了 Parcelable 接口的对象

  • AIDL :所有的AIDL接口本身也可以在 AIDL 文件中使用

注意:

  1. 自定义的 Parcelable 对象和 AIDL 对象必须要显式 import 进来( eg :下文的 IBookManager.aidl)

  2. 如果在 AIDL 文件种使用到了自定义的 Parcelable 对象,必须要新建一个和它同名的 AIDL 文件,并声明它为 Parcelable 类型。(eg: Book.aidl)

2、AIDL的详细使用 [ Kotlin ]:

? Book类使用 Parcelable 接口:

open class Book(var bookName: String?, var BookId: Int) : Parcelable {
    constructor(parcel: Parcel) : this(parcel.readString(),parcel.readInt()) {
    }override fun writeToParcel(parcel: Parcel, flags: Int) {
    parcel.writeString(bookName)parcel.writeInt(BookId)}override fun describeContents(): Int {
    return 0}companion object CREATOR : Parcelable.Creator<Book> {
    override fun createFromParcel(parcel: Parcel): Book {
    return Book(parcel)}override fun newArray(size: Int): Array<Book?> {
    return arrayOfNulls(size)}}override fun toString(): String {
    return " [BookName:$bookName ; BookId : $BookId ] "}
}
2.1 AIDL接口的创建
// IBookManager.aidl
package com.example.aidltest;import com.example.aidltest.Book;// Declare any non-default types here with import statementsinterface IBookManager {
    /** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/List<Book> getBookList();void addBook(in Book book);//增加订阅功能void registerListener(IOnNewBookArrivedListener listener);void unregisterListener(IOnNewBookArrivedListener listener);
}
// Book.aidl
package com.example.aidltest;// Declare any non-default types here with import statementsparcelable Book;
2.2 服务端的实现
//BookManagerService.kt
open class BookManagerService : Service() {
    private val TAG = "BMS"private var mBookList = CopyOnWriteArrayList<Book>()private var mIsServiceDestoryed = AtomicBoolean(false)//订阅者列表//RemoteCallbackList是系统专门提供的用于删除跨进程 listener 的接口private var mListenerList = RemoteCallbackList<IOnNewBookArrivedListener>();private val  mBinder = object : IBookManager.Stub(){
    override fun getBookList(): MutableList<Book> {
    return mBookList}override fun addBook(book: Book?) {
    mBookList.add(book)}override fun registerListener(listener: IOnNewBookArrivedListener?) {
    mListenerList.register(listener)}override fun unregisterListener(listener: IOnNewBookArrivedListener?) {
    mListenerList.unregister(listener)}}override fun onCreate() {
    super.onCreate()mBookList.add(Book("Android疯狂讲义",1))mBookList.add(Book("Android开发艺术探索",2))Thread(ServiceWorker()).start()}override fun onDestroy() {
    mIsServiceDestoryed.set(true)super.onDestroy()}override fun onBind(intent: Intent): IBinder {
    return mBinder;}//通知订阅者新书已到达private fun onNewBookArrived(book:Book){
    mBookList.add(book)var N = mListenerList.beginBroadcast()for(i in 0 until N ){
    var listener = mListenerList.getBroadcastItem(i)listener?.onNewBookArrived(book)}mListenerList.finishBroadcast()}private inner class ServiceWorker : Runnable{
    override fun run() {
    while (!mIsServiceDestoryed.get()){
    Thread.sleep(1000)var bookId = mBookList.size + 1var  newBook = Book("new book#$bookId",bookId)onNewBookArrived(newBook)}}}}
2.3 客户端的实现
//BookManagerActivity.kt
class BookManagerActivity : AppCompatActivity() {
    companion object{
    const val MESSAGE_NEW_BOOK_ARRIVED = 1const val TAG = "BookManagerActivity"}private var mRemoteBookManager : IBookManager ?= nullprivate var mHandler :Handler = object :Handler(Looper.getMainLooper()){
    override fun handleMessage(msg: Message) {
    when(msg?.what){
    MESSAGE_NEW_BOOK_ARRIVED -> {
    Log.d(TAG,"receive new book : ${
      msg.obj}")}else ->{
    super.handleMessage(msg)}}}}private val mConnection = object : ServiceConnection{
    override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
    val bookManager = IBookManager.Stub.asInterface(p1)mRemoteBookManager = bookManagervar list = bookManager.bookListLog.i(TAG,"query book list,list type:${
      list::class.java.canonicalName}")Log.i(TAG,list.toString())//在客户端调用一下 addBookvar book = Book("Android进阶之光",3)bookManager.addBook(book)var newList = bookManager.bookListLog.i(TAG,newList.toString())//订阅消息bookManager.registerListener(mIOnNewBookArrivedListener)}override fun onServiceDisconnected(p0: ComponentName?) {
    mRemoteBookManager = nullLog.e(TAG,"binder died")}}private var mIOnNewBookArrivedListener = object : IOnNewBookArrivedListener.Stub(){
    override fun onNewBookArrived(newBook: Book?) {
    mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRIVED,newBook).sendToTarget()}}override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val intent = Intent(this,BookManagerService::class.java)bindService(intent,mConnection, Context.BIND_AUTO_CREATE)}override fun onDestroy() {
    if(mRemoteBookManager!=null&& mRemoteBookManager!!.asBinder().isBinderAlive){
    Log.i(TAG,"unregister listen:$mIOnNewBookArrivedListener")mRemoteBookManager!!.unregisterListener(mIOnNewBookArrivedListener)}unbindService(mConnection)super.onDestroy()}
}
2.4 注册服务
        <serviceandroid:name=".BookManagerService"android:enabled="true"android:exported="true"android:process=":remote"></service>
2.5 查看logcat
//使用CopyOnWriteArrayList来进行自动的线程同步
//但Binder会按照List的规范去访问数据并最终形成 ArrayList 传给客户端
2021-04-01 19:57:32.169 17720-17720/com.example.aidltest I/BookManagerActivity:
query book list,list type:java.util.ArrayList2021-04-01 19:57:32.169 17720-17720/com.example.aidltest I/BookManagerActivity:
[ [BookName:Android疯狂讲义 ; BookId : 1 ] ,  [BookName:Android开发艺术探索 ; BookId : 2 ] ]//客户端成功添加新书
20:19:20.225 17984-17984/com.example.aidltest I/BookManagerActivity: [ [BookName:Android疯狂讲义 ; BookId : 1 ] ,  [BookName:Android开发艺术探索 ; BookId : 2 ] ,  [BookName:Android进阶之光 ; BookId : 3 ] ]//每隔1s打印一次数据[服务端每隔1s发送给订阅消息的订阅者]
2021-04-01 21:29:36.181 20109-20109/com.example.aidltest D/BookManagerActivity: receive new book :  [BookName:new book#4 ; BookId : 4 ] 
2021-04-01 21:29:37.183 20109-20109/com.example.aidltest D/BookManagerActivity: receive new book :  [BookName:new book#5 ; BookId : 5 ] 
2021-04-01 21:29:38.187 20109-20109/com.example.aidltest D/BookManagerActivity: receive new book :  [BookName:new book#6 ; BookId : 6 ] 
2021-04-01 21:29:39.192 20109-20109/com.example.aidltest D/BookManagerActivity: receive new book :  [BookName:new book#7 ; BookId : 7 ] 

  相关解决方案