Kotlin跨进程通信AIDL与Messenger
2021-09-064.6k 阅读
Kotlin跨进程通信之AIDL
在Android开发中,不同进程之间的通信是一个常见的需求。AIDL(Android Interface Definition Language)是一种Android特有的接口定义语言,用于在不同进程间进行通信。它基于Binder机制实现,能让一个Android应用中的不同进程共享对象。
AIDL基础概念
- Binder机制:
- Binder是Android系统中一种高效的进程间通信(IPC)机制。它基于Client - Server架构,允许在不同进程间传递数据和调用远程方法。Binder驱动在内核空间,负责管理进程间通信的连接、数据传输等操作。
- 例如,当一个应用的一个进程(Client)想要调用另一个进程(Server)中的方法时,Binder机制通过在内核空间建立通信通道,将Client的请求传递给Server,并将Server的响应返回给Client。
- AIDL文件:
- AIDL文件定义了跨进程通信的接口。它使用一种类似Java接口的语法,但有一些特定的规则。AIDL文件通常以.aidl为扩展名。
- 例如,定义一个简单的AIDL接口如下:
// IMyAidlInterface.aidl
package com.example.aidl;
// Declare any non - primitive types here with import statements
interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
- 在上述代码中,定义了一个名为
IMyAidlInterface
的接口,包含一个basicTypes
方法,接受多种基本数据类型和String
类型的参数。
AIDL使用步骤
- 定义AIDL文件:
- 首先,在
src/main/aidl
目录下创建AIDL文件(如果没有aidl
目录,需要手动创建)。 - 例如,定义一个用于获取当前时间的AIDL接口
ITimeService.aidl
:
- 首先,在
package com.example.aidl;
interface ITimeService {
long getCurrentTime();
}
- 这里定义了一个
getCurrentTime
方法,返回当前时间的毫秒数。
- 生成Java代码:
- 当AIDL文件编写完成后,Android Studio会自动生成对应的Java代码。生成的Java代码在
build/generated/source/aidl
目录下。 - 以
ITimeService.aidl
为例,生成的Java代码如下(简化版):
- 当AIDL文件编写完成后,Android Studio会自动生成对应的Java代码。生成的Java代码在
package com.example.aidl;
public interface ITimeService extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements com.example.aidl.ITimeService {
private static final java.lang.String DESCRIPTOR = "com.example.aidl.ITimeService";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public static com.example.aidl.ITimeService asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!= null) && (iin instanceof com.example.aidl.ITimeService))) {
return ((com.example.aidl.ITimeService) iin);
}
return new com.example.aidl.ITimeService.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getCurrentTime: {
data.enforceInterface(DESCRIPTOR);
long _result = this.getCurrentTime();
reply.writeNoException();
reply.writeLong(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.aidl.ITimeService {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public long getCurrentTime() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
long _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getCurrentTime, _data, _reply, 0);
_reply.readException();
_result = _reply.readLong();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_getCurrentTime = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public long getCurrentTime() throws android.os.RemoteException;
}
- 这段生成的代码包含了Stub类和Proxy类。Stub类继承自
Binder
,实现了AIDL接口,用于在服务端处理跨进程调用。Proxy类实现了AIDL接口,用于在客户端代理远程服务调用。
- 创建服务端Service:
- 在服务端应用中,创建一个继承自
Service
的类,并实现AIDL接口。 - 例如:
- 在服务端应用中,创建一个继承自
package com.example.aidlserver
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.os.RemoteException
import com.example.aidl.ITimeService
class TimeService : Service() {
private val binder = object : ITimeService.Stub() {
@Throws(RemoteException::class)
override fun getCurrentTime(): Long {
return System.currentTimeMillis()
}
}
override fun onBind(intent: Intent): IBinder {
return binder
}
}
- 在上述代码中,
TimeService
类继承自Service
,并在内部创建了一个实现ITimeService
接口的binder
对象。onBind
方法返回这个binder
,以便客户端可以绑定到该服务。
- 在客户端绑定服务并调用方法:
- 在客户端应用中,需要绑定到服务端的
Service
,并获取AIDL接口的实例来调用方法。 - 例如:
- 在客户端应用中,需要绑定到服务端的
package com.example.aidlclient
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.os.RemoteException
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.example.aidl.ITimeService
class MainActivity : AppCompatActivity() {
private var timeService: ITimeService? = null
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
timeService = ITimeService.Stub.asInterface(service)
try {
val currentTime = timeService?.getCurrentTime()
findViewById<TextView>(R.id.time_text).text = "Current Time: $currentTime"
} catch (e: RemoteException) {
e.printStackTrace()
}
}
override fun onServiceDisconnected(name: ComponentName) {
timeService = null
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val intent = Intent()
intent.component = ComponentName("com.example.aidlserver", "com.example.aidlserver.TimeService")
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
override fun onDestroy() {
super.onDestroy()
unbindService(connection)
}
}
- 在上述代码中,
MainActivity
通过bindService
方法绑定到服务端的TimeService
。ServiceConnection
的onServiceConnected
方法在服务连接成功时被调用,通过ITimeService.Stub.asInterface
获取ITimeService
的实例,并调用getCurrentTime
方法获取当前时间并显示在界面上。onServiceDisconnected
方法在服务断开连接时被调用,将timeService
置为null
。
AIDL传递自定义对象
- 定义自定义对象的AIDL文件:
- 如果需要在AIDL中传递自定义对象,首先要为自定义对象创建对应的AIDL文件。例如,定义一个
Person
类:
- 如果需要在AIDL中传递自定义对象,首先要为自定义对象创建对应的AIDL文件。例如,定义一个
data class Person(
val name: String,
val age: Int
)
- 然后创建
Person.aidl
文件:
package com.example.aidl;
// 注意,这里必须显式import,即使在同一个包下
import com.example.aidl.Person;
parcelable Person;
- 在上述
Person.aidl
文件中,使用parcelable
关键字声明Person
类是可序列化的。
- 实现
Parcelable
接口:Person
类需要实现Parcelable
接口,以便在进程间传递。
import android.os.Parcel
import android.os.Parcelable
data class Person(
val name: String,
val age: Int
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString()?: "",
parcel.readInt()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name)
parcel.writeInt(age)
}
override fun describeContents(): Int {
return 0
}
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)
}
}
}
- 在AIDL接口中使用自定义对象:
- 修改AIDL接口,使其可以接受或返回
Person
对象。例如:
- 修改AIDL接口,使其可以接受或返回
package com.example.aidl;
import com.example.aidl.Person;
interface IMyService {
Person getPerson();
}
- 服务端实现和客户端调用:
- 在服务端实现
IMyService
接口:
- 在服务端实现
package com.example.aidlserver
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.os.RemoteException
import com.example.aidl.IMyService
import com.example.aidl.Person
class MyService : Service() {
private val binder = object : IMyService.Stub() {
@Throws(RemoteException::class)
override fun getPerson(): Person {
return Person("John", 30)
}
}
override fun onBind(intent: Intent): IBinder {
return binder
}
}
- 在客户端绑定服务并调用方法:
package com.example.aidlclient
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.os.RemoteException
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.example.aidl.IMyService
import com.example.aidl.Person
class MainActivity : AppCompatActivity() {
private var myService: IMyService? = null
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
myService = IMyService.Stub.asInterface(service)
try {
val person = myService?.getPerson()
findViewById<TextView>(R.id.person_text).text = "Name: ${person?.name}, Age: ${person?.age}"
} catch (e: RemoteException) {
e.printStackTrace()
}
}
override fun onServiceDisconnected(name: ComponentName) {
myService = null
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val intent = Intent()
intent.component = ComponentName("com.example.aidlserver", "com.example.aidlserver.MyService")
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
override fun onDestroy() {
super.onDestroy()
unbindService(connection)
}
}
- 通过以上步骤,就可以在AIDL跨进程通信中传递自定义对象。
Kotlin跨进程通信之Messenger
Messenger是Android提供的一种基于Handler的跨进程通信方式。它相对AIDL来说,实现起来较为简单,适合在不需要复杂功能的跨进程通信场景中使用。
Messenger基础概念
- Handler和Message:
- Handler是Android中用于处理异步消息的机制。它可以发送和处理
Message
对象。Message
是一个用于携带数据的对象,通常包含一些整型字段和一个Bundle
对象来存储数据。 - 例如,在主线程中创建一个
Handler
:
- Handler是Android中用于处理异步消息的机制。它可以发送和处理
val handler = Handler(Looper.getMainLooper()) { message ->
when (message.what) {
1 -> {
// 处理消息类型1的逻辑
}
2 -> {
// 处理消息类型2的逻辑
}
}
true
}
- 然后可以通过
handler
发送Message
:
val message = Message.obtain()
message.what = 1
message.data.putString("key", "value")
handler.sendMessage(message)
- Messenger:
- Messenger基于
Handler
实现,它可以将Handler
包装成一个IBinder
对象,从而可以在不同进程间传递。一个进程可以通过Messenger
向另一个进程发送Message
,接收方通过关联的Handler
处理这些Message
。
- Messenger基于
Messenger使用步骤
- 服务端实现:
- 在服务端创建一个
Handler
来处理客户端发送的消息,并将其包装成Messenger
。 - 例如:
- 在服务端创建一个
package com.example.messengerserver
import android.app.Service
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.IBinder
import android.os.Message
import android.os.Messenger
import android.os.RemoteException
import android.widget.Toast
import androidx.annotation.NonNull
class MessengerService : Service() {
private val handler = object : Handler() {
override fun handleMessage(@NonNull msg: Message) {
when (msg.what) {
1 -> {
val data = msg.data.getString("key")
Toast.makeText(this@MessengerService, "Received: $data", Toast.LENGTH_SHORT).show()
}
}
}
}
private val messenger = Messenger(handler)
override fun onBind(intent: Intent): IBinder {
return messenger.binder
}
}
- 在上述代码中,
MessengerService
类继承自Service
。handler
用于处理客户端发送的消息,当接收到消息类型为1的消息时,从Message
的data
中取出字符串并显示一个Toast
。messenger
将handler
包装成Messenger
,onBind
方法返回messenger
的binder
,以便客户端可以绑定到该服务。
- 客户端绑定服务并发送消息:
- 在客户端绑定到服务端的
Service
,获取Messenger
实例,并发送Message
。 - 例如:
- 在客户端绑定到服务端的
package com.example.messengerclient
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.os.Message
import android.os.Messenger
import android.os.RemoteException
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
private var messenger: Messenger? = null
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
messenger = Messenger(service)
Toast.makeText(this@MainActivity, "Service Connected", Toast.LENGTH_SHORT).show()
}
override fun onServiceDisconnected(name: ComponentName) {
messenger = null
Toast.makeText(this@MainActivity, "Service Disconnected", Toast.LENGTH_SHORT).show()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val sendButton = findViewById<Button>(R.id.send_button)
val editText = findViewById<EditText>(R.id.edit_text)
sendButton.setOnClickListener {
val message = Message.obtain()
message.what = 1
val data = Bundle()
data.putString("key", editText.text.toString())
message.data = data
try {
messenger?.send(message)
} catch (e: RemoteException) {
e.printStackTrace()
}
}
val intent = Intent()
intent.component = ComponentName("com.example.messengerserver", "com.example.messengerserver.MessengerService")
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
override fun onDestroy() {
super.onDestroy()
unbindService(connection)
}
}
- 在上述代码中,
MainActivity
通过bindService
方法绑定到服务端的MessengerService
。ServiceConnection
的onServiceConnected
方法在服务连接成功时被调用,获取Messenger
实例。点击sendButton
时,创建一个Message
,设置消息类型为1,并将EditText
中的内容放入Message
的data
中,然后通过Messenger
发送消息。onServiceDisconnected
方法在服务断开连接时被调用,将messenger
置为null
。
Messenger双向通信
- 服务端接收客户端的Messenger并发送消息:
- 服务端不仅要处理客户端发送的消息,还需要能够向客户端发送消息。这就需要客户端将自己的
Messenger
发送给服务端。 - 首先,修改服务端的
Handler
来接收客户端的Messenger
:
- 服务端不仅要处理客户端发送的消息,还需要能够向客户端发送消息。这就需要客户端将自己的
package com.example.messengerserver
import android.app.Service
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.IBinder
import android.os.Message
import android.os.Messenger
import android.os.RemoteException
import android.widget.Toast
import androidx.annotation.NonNull
class MessengerService : Service() {
private var clientMessenger: Messenger? = null
private val handler = object : Handler() {
override fun handleMessage(@NonNull msg: Message) {
when (msg.what) {
1 -> {
val data = msg.data.getString("key")
Toast.makeText(this@MessengerService, "Received: $data", Toast.LENGTH_SHORT).show()
clientMessenger = msg.replyTo
sendResponse()
}
}
}
}
private val messenger = Messenger(handler)
private fun sendResponse() {
val message = Message.obtain()
message.what = 2
val data = Bundle()
data.putString("response", "Message received successfully")
message.data = data
try {
clientMessenger?.send(message)
} catch (e: RemoteException) {
e.printStackTrace()
}
}
override fun onBind(intent: Intent): IBinder {
return messenger.binder
}
}
- 在上述代码中,
clientMessenger
用于保存客户端的Messenger
。当接收到客户端发送的消息时,从Message
的replyTo
字段获取客户端的Messenger
,并调用sendResponse
方法向客户端发送响应消息。
- 客户端处理服务端发送的消息:
- 客户端需要创建一个
Handler
来处理服务端发送的消息,并将这个Handler
包装成Messenger
发送给服务端。 - 修改客户端代码如下:
- 客户端需要创建一个
package com.example.messengerclient
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.Handler
import android.os.IBinder
import android.os.Message
import android.os.Messenger
import android.os.RemoteException
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
private var messenger: Messenger? = null
private val clientHandler = object : Handler() {
override fun handleMessage(msg: Message) {
when (msg.what) {
2 -> {
val data = msg.data.getString("response")
Toast.makeText(this@MainActivity, "Response: $data", Toast.LENGTH_SHORT).show()
}
}
}
}
private val clientMessenger = Messenger(clientHandler)
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
messenger = Messenger(service)
Toast.makeText(this@MainActivity, "Service Connected", Toast.LENGTH_SHORT).show()
sendInitialMessage()
}
override fun onServiceDisconnected(name: ComponentName) {
messenger = null
Toast.makeText(this@MainActivity, "Service Disconnected", Toast.LENGTH_SHORT).show()
}
}
private fun sendInitialMessage() {
val message = Message.obtain()
message.what = 1
val data = Bundle()
data.putString("key", "Hello from client")
message.data = data
message.replyTo = clientMessenger
try {
messenger?.send(message)
} catch (e: RemoteException) {
e.printStackTrace()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val sendButton = findViewById<Button>(R.id.send_button)
val editText = findViewById<EditText>(R.id.edit_text)
sendButton.setOnClickListener {
val message = Message.obtain()
message.what = 1
val data = Bundle()
data.putString("key", editText.text.toString())
message.data = data
message.replyTo = clientMessenger
try {
messenger?.send(message)
} catch (e: RemoteException) {
e.printStackTrace()
}
}
val intent = Intent()
intent.component = ComponentName("com.example.messengerserver", "com.example.messengerserver.MessengerService")
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
override fun onDestroy() {
super.onDestroy()
unbindService(connection)
}
}
- 在上述代码中,
clientHandler
用于处理服务端发送的消息,当接收到消息类型为2的消息时,从Message
的data
中取出响应字符串并显示一个Toast
。clientMessenger
将clientHandler
包装成Messenger
。在sendInitialMessage
方法和sendButton
的点击事件中,将clientMessenger
放入Message
的replyTo
字段发送给服务端,以便服务端可以向客户端发送响应消息。
AIDL与Messenger的比较
- 功能复杂度:
- AIDL功能强大,可以定义复杂的接口,支持方法调用、自定义对象传递等,适用于需要复杂跨进程通信功能的场景,如远程服务调用等。
- Messenger相对简单,主要基于消息传递,适合在不需要复杂功能,只需要简单消息通信的场景中使用,如在不同进程间传递简单的通知等。
- 实现难度:
- AIDL的实现相对复杂,需要编写AIDL文件,处理生成的Java代码,在服务端和客户端进行复杂的绑定和调用操作。
- Messenger基于
Handler
,实现较为简单,对开发者的要求相对较低。
- 性能:
- AIDL基于Binder机制,性能较高,在处理大量数据和频繁调用时表现较好。
- Messenger在性能上相对AIDL略逊一筹,因为它是基于消息队列的方式,在处理复杂操作时可能会有一定的延迟。
在实际开发中,应根据具体的需求选择合适的跨进程通信方式。如果需要实现复杂的远程服务调用和数据交互,AIDL是较好的选择;如果只是简单的消息传递,Messenger则更为合适。