在上一篇解说使用 AIDL进行跨进程传数据的文章中,有提到了会解说 AIDL产生的接口类,所以在这一篇文章,
就是学习接口类大致是如何构成的,还有这个接口怎麽完成跨进程的工作。AIDL类产生的接口类代码大约像这样…
public interface IMyInterface extends IInterface {
public int getPid() throws RemoteException;
public String getServiceName() throws RemoteException;
public void makeSingingService() throws RemoteException;
public abstract static class Stub extends Binder implements IMyInterface {
private static final String DESCRIPTOR = "com.example.shanwu.interprocesscomm.IMyInterface";
static final int TRANSACTION_getPid = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getServiceName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_makeSingingService = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
public Stub() {
attachInterface(this, DESCRIPTOR);
}
public static IMyInterface asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (iin != null && iin instanceof IMyInterface) {
Log.d("guang", "iin != null && iin instanceof IMyInterface --" + String.valueOf(android.os.Process.myPid()));
return (IMyInterface) iin;
} else {
Log.d("guang", "lin else" + String.valueOf(android.os.Process.myPid()));
return new IMyInterface.Stub.Proxy(obj);
}
}
@Override
public IBinder asBinder() {
return this;
}
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case INTERFACE_TRANSACTION:
Log.d("guang","INTERFACE_TRANSACTION -- stub "+ String.valueOf(android.os.Process.myPid()));
reply.writeString(DESCRIPTOR);
return true;
case TRANSACTION_getPid:
Log.d("guang","TRANSACTION_getPid -- stub "+ String.valueOf(android.os.Process.myPid()));
data.enforceInterface(DESCRIPTOR);
int result = this.getPid();
reply.writeNoException();
reply.writeInt(result);
return true;
case TRANSACTION_getServiceName:
Log.d("guang","TRANSACTION_getServiceName -- stub "+ String.valueOf(android.os.Process.myPid()));
data.enforceInterface(DESCRIPTOR);
String serviceName = this.getServiceName();
reply.writeNoException();
reply.writeString(serviceName);
return true;
case TRANSACTION_makeSingingService:
Log.d("guang","TRANSACTION_makeSingingService -- stub "+ String.valueOf(android.os.Process.myPid()));
data.enforceInterface(DESCRIPTOR);
this.makeSingingService();
reply.writeNoException();
return true;
}
return super.transact(code, data, reply, flags);
}
private static class Proxy implements IMyInterface {
private IBinder mRemote;
Proxy(IBinder remote) {
mRemote = remote;
}
@Override
public IBinder asBinder() {
return mRemote;
}
public String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public int getPid() throws RemoteException {
Log.d("guang", "getPid -- proxy " + String.valueOf(android.os.Process.myPid()));
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
int result;
try {
data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getPid, data, reply, 0);
reply.readException();
result = reply.readInt();
} finally {
// ensure we recycle parcels back to pool, but why ?
data.recycle();
reply.recycle();
}
return result;
}
@Override
public String getServiceName() throws RemoteException {
Log.d("guang", "getServiceName -- proxy " + String.valueOf(android.os.Process.myPid()));
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
String result;
try {
data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getServiceName, data, reply, 0);
reply.readException();
result = reply.readString();
} finally {
data.recycle();
reply.recycle();
}
return result;
}
@Override
public void makeSingingService() throws RemoteException {
Log.d("guang", "makeSingingService -- proxy " + String.valueOf(android.os.Process.myPid()));
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_makeSingingService, data, reply, 0);
reply.readException();
} finally {
Log.d("guang", "makeSingingService finally-- proxy " + String.valueOf(android.os.Process.myPid()));
data.recycle();
reply.recycle();
}
}
}
}
}
突然一看,感觉相当复雜,但是稍微整理一下,它的架构就大约清楚了…
它是由二个内部类构成的,一个叫 Stub,一个叫 Proxy。Stub是一个 abstract class 需要提供服务的 Service 实现相关的方法
private final IMyInterface.Stub mBinder = new IMyInterface.Stub() {
@Override
public int getPid() throws RemoteException {
return android.os.Process.myPid();
}
@Override
public String getServiceName() throws RemoteException {
return "Worker Service~ ";
}
@Override
public void makeSingingService() {
mHandler.sendEmptyMessage(MSG_START_SING);
}
};
并且在建立连结回调 onBind()的时候,返回此 Stub 对象
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
而 Proxy 则是一个内部静态类实现了该接口,成为使用服务的接口对象代理,而在调用bindService()时,回调 onServiceConnected() 时初始化
mServiceConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mService = IMyInterface.Stub.asInterface(iBinder);
Log.d("guang", "onServiceConnected");
mIsBind = true;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.d("guang", "onServiceDisconnected");
mIsBind = false;
}
};
然後在客户端调这个远端的 Proxy 对象使用
case R.id.btn_sing:
if (mIsBind) {
try {
mWorkerId = mService.getPid();
Toast.makeText(MainActivity.this, mWorkerId + "", Toast.LENGTH_LONG).show();
mService.makeSingingService();
} catch (RemoteException e) {
Log.e("guang", "Service is dead " + e);
}
}
break;
最後,我们可以将它们的沟通流程简化成下面的一张图
这样看起来,会不会简单一些? 有问题欢迎一起讨论~~
范例代码都在 GitHub