问:Android中的IPC(进程间通信)机制?
答:进程间通信即:跨进程的通信。有以下几种:
1、使用Bundle。四大组件中Activity、Service、BroadcastReceiver都支持在Intent中传递Bundle数据。由于Bundle实现了Parcelable接口,所以它可以很方便的在不同的进程间传输数据。当然我们传输的数据必须能够被序列化,比如基本类型、实现了Parcelable接口的对象、实现了Serializable接口的对象以及一些Android支持的特殊对象。Bundle只能单向的传递数据。
2、使用共享文件。两个进程通过读写同一个文件来交换数据。缺点在于如果两个进程同时并发读写就会造成数据不完整或数据不正确的问题。
3、使用Messenger。它的底层实现是通过AIDL的方式,使用Handler机制,携带Message对象来进行不同进程间数据通信的,所以Messenger不支持并发,只能串行,多次发送消息只能一条条处理。使用方式:
//服务(Service)端:
//1、进程中创建一个Service来处理其他进程的连接请求
class IPCService:Service(){
//创建一个Handler来进行消息处理
private val mHandler = object : Handler(){
@SuppressLint("HandlerLeak")
override fun handleMessage(msgfromClient: Message) {
//doSomething()
//获取用户端的信使对象
val msgToClient = Message.obtain(msgfromClient)
//msgToClient doSomething()
//获取客户端的Messenger对象
val messengerToClient = msgToClient.replyTo
//向客户端发送消息
messengerToClient.send(msgToClient)
}
}
//用mHandler对象来创建一个Messenger对象
private val mMessenger = Messenger(mHandler)
override fun onBind(p0: Intent?): IBinder? {
//在onBind方法中返回Ibinder对象
return mMessenger.binder
}
}
//客户(Client)端
class IPCClientActivity: AppCompatActivity() {
private val mMessenger = Messenger(object : Handler(){
override fun handleMessage(msgFromServer: Message) {
super.handleMessage(msgFromServer)
//接收服务端发送过来的消息 doSomething()
}
})
//服务端Messenger对象
private var mServerMessenger: Messenger? = null
private val mCon = object : ServiceConnection{
override fun onServiceDisconnected(p0: ComponentName?) {
mServerMessenger = null
}
override fun onServiceConnected(p0: ComponentName?, binder: IBinder?) {
//获取服务端Messenger对象
mServerMessenger = Messenger(binder)
}
}
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
//绑定服务端
val intent = Intent()
intent.action = "xxx" //服务端在manifest中注册的action
bindService(intent, mCon, Context.BIND_AUTO_CREATE)
//获取Message对象
val msgFromClient = Message.obtain()
//将用户端Messenger对象添加到Message中,服务端获取,用来回传消息
msgFromClient.replyTo = mMessenger
//客户端向服务端发送消息
mServerMessenger?.send(msgFromClient)
}
override fun onDestroy() {
super.onDestroy()
//解除绑定
unbindService(mCon)
}
}
4、使用AIDL:它是一种IDL语言,用于生成Android设备上的两个进程之间进行通信的的代码。AIDL可以实现多线程并发调用,同时可以在Service中暴露出来一些方法让客户端直接调用,这两点就和Messenger有很大的区别,Messenger只能单线程、传递Message对象进行通信。
1、创建aidl文件 -- 在AndroidStudio中,点击项目中main目录,右键new->AIDL->AIDL File 生成相同包名相同目录的aidl文件:里面生成一个方法,其实是告诉你支持什么类型的数据。
2、如果要在AIDL接口文件中使用AIDL对象,必须显式的 import 进来,即使它们在同一个包内,还有如果在AIDL接口文件用到了Parcelable对象,必须新建一个和它同名的AIDL文件,并在其中声明它为parcelable类型
//声明一个User类:
@Parcelize
data class User(
var name:String
) : Parcelable
//声明一个User.aidl 文件
// User.aidl
package com.xyx.studydemo;
// Declare any non-default types here with import statements
parcelable User;
//修改ImyAidlInterface.aidl为IUserManager.aidl, 修改方法
package com.xyx.studydemo;
import com.xyx.studydemo.User;
interface IUserManager {
User getUser(String name);
}
通过 Build -> ReBuild Project后生成IUsermanager.java代码:
image.png
3、创建Service :
class AIDLService : Service(){
//1、实现Stub类中的getUser方法
private val mBinder:IUserManager.Stub = object : IUserManager.Stub(){
override fun getUser(name: String?): User {
return User("name")
}
}
override fun onBind(p0: Intent?): IBinder? {
//在onBinder方法中返回Stub类的实现,Stub类继承自Binder,Binder实现了IBinder,这样返回是没问题的
return mBinder
}
}
本地Activity使用时:
class AIDLActivity : AppCompatActivity(){
private val mCon = object : ServiceConnection{
override fun onServiceDisconnected(p0: ComponentName?) {
//与服务端断开
}
override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
//连接上服务端
//把服务端返回的Binder引用,通过Stub.asInterface方法包装成本地代理类
// IUserManager.Stub.Proxy,Proxy类实现了IUserManager
val userManager = IUserManager.Stub.asInterface(p1)
//通过本地代理对象获取远端服务端的方法
val user = userManager.getUser("name")
}
}
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
//绑定服务端
bindService(Intent(this, AIDLService::class.java), mCon, Context.BIND_AUTO_CREATE)
}
override fun onDestroy() {
super.onDestroy()
unbindService(mCon)
}
}
通过AIDL的方式可以获取服务端的代理对象,直接调用服务端方法,底层还是利用Binder机制进行通信的。
5、使用ContenProvider、BroadcastReceiver:例如联系人数据的获取、开机广播等等也都是使用了进程通信。它们也是属于进程通信的一种方式
6、socket套接字:实际上是一种网络通信,但线程通信,在应用启动过程中,通知Zygote进程fork一个新进程时就是使用socket进行通信的(fork是Unix操作系统上创建进程的方法,同时fork不允许存在多线程,所以创建新进程时使用socket,防止死锁)
问:什么是Binder
答:Binder是用于进程间通信的一种方式,Android底层其实是Linux系统,且Linux系统也提供了很多的进程间通信方式:如socket之类的。Binder基于内存映射原理(mmap)实现。AIDL就是基于Binder实现,同时应用启动过程、四大组件等等很多地方都存在Binder的身影。Binder跨进程通信,主要就是利用进程间内核空间共享数据来实现的。Binder驱动主要就是在内核空间,通过Binder驱动实现进程间数据共享。进程A给进程B发送消息:
1、进程A通过系统调用拷贝内容到内核空间。
2、由于内核空间与进程B做了内存映射,因此进程B能够知道内核空间的信息。 如图:
网友评论