在Android 应用开发过程中涉及到进程间通信的场景不多,但是随着进程化开发的实现,单APP多进程的情况也越来越多。这就涉及到IPC进程间通信,而Binder 就是其中的一种,Android中很多情况 IPC 通信都是通过 Binder 实现的,其底层相对复杂,在应用层,我们可以理解Binder 就是一个Java 类,在进程间通信的 client -> service 结构中数据的传递是通过Binder 来实现的。而Android 为了方便我们实现这一功能 提供了AIDL 文件 Android Interface Definition Language(安卓接口定义语言)
要实现进程间通信我们需要创建 service 端和 client 端
1.创建AIDL 文件
// IServiceInterface.aidl
package com.fyh.aidl;
// Declare any non-default types here with import statements
interface IServiceInterface {
/**
* 这边默认生成的一个方法 可以不用管,这里写个getData() 方法获取数据
*/
String getData();
}
当创建好AIDL文件 编译后,会自动生成一个 对应名称的Java 接口类
public interface IServiceInterface extends android.os.IInterface
2.创建 service
public class AIDLService extends Service {
public AIDLService() {
}
@Override
public IBinder onBind(Intent intent) {
return stub;
}
//这里 Stub 是一个继承 IBinder 的抽象类,所以 IServiceInterface.Stub 是我们对 IBinder
//的具体实现,而我们实现的方法就是服务端提供一个方法传递数据"{'data':'AIDLServiceTest'}
IServiceInterface.Stub stub = new IServiceInterface.Stub() {
@Override
public String getData() throws RemoteException {
String s = "{'data':'AIDLServiceTest'}";
return s;
}
};
}
3.创建 client 端
//创建service 链接
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iServiceInterface = IServiceInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
iServiceInterface = null;
}
};
//绑定
public void bindService(Context context) {
Intent intent = new Intent();
intent.setAction("com.fyh.aidl");
intent.setPackage("com.fyh.aidl.service");
context.bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
//解绑
public void unbindService(Context context) {
if (null == iServiceInterface) {
return;
}
context.unbindService(connection);
iServiceInterface = null;
}
//请求服务端数据
public String requestData() {
if (null == iServiceInterface) {
return null;
}
try {
String data = iServiceInterface.getData();
return data;
} catch (RemoteException e) {
e.printStackTrace();
}
return null;
}
输出的结果
通过使用 AIDL 我们会非常方便的实现进程间的通讯 同时我们可以看看自动生成的 IServiceInterface.java 文件是什么样的结构。
package com.fyh.aidl;
public interface IServiceInterface extends android.os.IInterface{
public static class Default implements com.fyh.aidl.IServiceInterface{
@Override
public java.lang.String getData() throws android.os.RemoteException{
return null;
}
@Override
public android.os.IBinder asBinder() {
return null;
}
}
public static abstract class Stub extends android.os.Binder implements com.fyh.aidl.IServiceInterface{
private static final java.lang.String DESCRIPTOR = "com.fyh.aidl.IServiceInterface";
public Stub(){
this.attachInterface(this, DESCRIPTOR);
}
public static com.fyh.aidl.IServiceInterface asInterface(android.os.IBinder obj){
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.fyh.aidl.IServiceInterface))) {
return ((com.fyh.aidl.IServiceInterface)iin);
}
return new com.fyh.aidl.IServiceInterface.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{
java.lang.String descriptor = DESCRIPTOR;
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
case TRANSACTION_getData:
{
data.enforceInterface(descriptor);
java.lang.String _result = this.getData();
reply.writeNoException();
reply.writeString(_result);
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com.fyh.aidl.IServiceInterface
{
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 java.lang.String getData() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_getData, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getData();
}
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public static com.fyh.aidl.IServiceInterface sDefaultImpl;
}
static final int TRANSACTION_getData = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
public static boolean setDefaultImpl(com.fyh.aidl.IServiceInterface impl) {
if (Stub.Proxy.sDefaultImpl == null && impl != null) {
Stub.Proxy.sDefaultImpl = impl;
return true;
}
return false;
}
public static com.fyh.aidl.IServiceInterface getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public java.lang.String getData() throws android.os.RemoteException;
}
在这个类中 实现了 com.fyh.aidl.IServiceInterface 接口的 情况有三种 Default Stub Proxy 。当default 的时候 返回的是null。
我们在 service 中实现的 是IServiceInterface.Stub stub = new IServiceInterface.Stub() 。从代码中我们可以看出 Stub 是一个继承了IBinder 实现了IServiceInterface 的抽象静态内部类,而具体的实现实在 AIDLService 中进行的。而这个 具体 的IBinder 时间对象 stub 会在客户端绑定的时候返回给客户端 。客户端会调用Stub中的静态方法asInterface,stub作为参数,最后拿到IServiceInterface接口对象 iServiceInterface 。
然后 if (((iin!=null)&&(iin instanceof com.fyh.aidl.IServiceInterface))) 判断客户端和服务端是否在同一个进程下,如果在同一进程那么asInterface()将返回Stub对象本身,因为此时根本不需要跨进称通信,那么直接调用Stub对象的接口就可以了。否则返回Stub.Proxy代理对象。该对象持有着远程的Binder引用,因为现在需要跨进程通信。
好了介绍的比较简单,文章主要是AIDL 的简单实现,顺便看看Android 为我们自动生成的类里面是什么样子的。如果要深入了解,还需要等深入的学习。
demo 地址 : https://github.com/fyhsgsgssg/AIDLTest