前言
上篇文章已經寫了aidl的使用步驟,記錄了在編寫過程中踩過的坑。使用還是比較簡單的,雖然步驟中的細節(jié)比較多。但是有沒有想過這個aidl到底是怎么工作的呢。我們可不可以脫離aidl文件來實現我們的跨進程通信功能呢?答案當然是可以的。這篇文章我們主要去分析一下aidl的大體實現步驟,最后我們自己脫離aidl文件,寫一個java文件來代替它。實現我們上一篇實現的功能。
正文
- 效果圖展示
gif
通過上篇的編寫,我們可以看到,aidl的工作流程圖這樣的。
1.在服務端的aidl文件中定義提供給客戶端調用的接口方法
2.在服務端的service定義一個binder,binder里面實現這個接口方法。然后在onbind方法中返回這個binder
3.在客戶端的ServiceConnection中拿到這個binder,然后調用binder的方法,這樣就實現了客戶端調用服務端的方法了。
我們從使用的地方開始看一下,首先看一下這個在客戶端拿到的這個IMyAidlInterface
binder = IMyAidlInterface.Stub.asInterface(service);
點擊去看
public static com.example.newserver.IMyAidlInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
//這里是從本地查看是否有這個IMyAidlInterface ,有的話直接返回
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.newserver.IMyAidlInterface))) {
return ((com.example.newserver.IMyAidlInterface)iin);
}
//沒有的話返回這個Proxy,一開始都是沒有的,我們去看看這個Proxy
return new com.example.newserver.IMyAidlInterface.Stub.Proxy(obj);
}
接著我們來看看這個Proxy
private static class Proxy implements com.example.newserver.IMyAidlInterface{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override
public android.os.IBinder asBinder()//這個方法就是返回這個Binder
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override public void addPerson(com.example.newserver.Person person) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((person!=null)) {
_data.writeInt(1);
person.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
//可以看到,客戶端調用的getPersonList就是這個方法
@Override
public java.util.List<com.example.newserver.Person> getPersonList() throws android.os.RemoteException
{
//_data是客戶端寫進去的參數,_reply是通過計算,服務返回來的值
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.newserver.Person> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
// 參數說明:
// code:Client進程請求方法標識符。即Server進程根據該標識確定所請求的目標方法
// data:目標方法的參數。(Client進程傳進來的)
// reply:目標方法執(zhí)行后的結果(返回給Client進程)
//第四個參數是一個 int 值,它的作用是設置進行 IPC 的模式,為 0 表示數據可以雙向流通,即 _reply 流可以正常的攜帶數據回來,如果為 1 的話那么數據將只能單向流通,從服務端回來的 _reply 流將不攜帶任何數據。
mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);
//讀取_reply值
_reply.readException();
//將reply值進行解序列化得到person的list,然后返回給客戶端
_result = _reply.createTypedArrayList(com.example.newserver.Person.CREATOR);
}
finally {
//data和reply的回收
_reply.recycle();
_data.recycle();
}
return _result;
}
}
上面我就拿getPersonList這個方法做了注釋,addPerson的流程也是一樣的。主要的方法就是調用了服務端傳過來的Binder的transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0),那為什么執(zhí)行了這個方法這個方法就執(zhí)行了服務的對應的接口方法了呢?其實是調用了IMyAidlInterface這個類里面的onTransact(code, data, reply, flags)方法,方法的參數值和Transact方法是一樣的。至于為什么是調用了這個onTrasact方法,這個就是系統(tǒng)底層的東西,這個并不得而知。這里就不去分析它了。
我們來看看onTransact(code, data, reply, flags)這個方法
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_addPerson:
{
data.enforceInterface(DESCRIPTOR);
com.example.newserver.Person _arg0;
if ((0!=data.readInt())) {
_arg0 = com.example.newserver.Person.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addPerson(_arg0);
reply.writeNoException();
return true;
}
//這個TRANSACTION_getPersonList就是transact方法的code參數,標志識別哪個方法
case TRANSACTION_getPersonList:
{
data.enforceInterface(DESCRIPTOR);
//這里就是關鍵了,是調用了真正實現的方法,也就是Service里面的getPersonLisst
java.util.List<com.example.newserver.Person> _result = this.getPersonList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
這里同樣分析getPersonList這個方法,由于這個IMyAidlInterface是一個接口
public interface IMyAidlInterface extends android.os.IInterface
當執(zhí)行getPersonList的時候,執(zhí)行了this.getPersonList()這個方法,這個方法是IMyAidlInterface這個接口定義的沒有實現的方法。
public void addPerson(com.example.newserver.Person person) throws android.os.RemoteException;
public java.util.List<com.example.newserver.Person> getPersonList() throws android.os.RemoteException;
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
}
那問題來了,到底哪里實現它呢?答案就是SerVice里面的IMyAidlInterface.Stub這個實現類,這個實現類是繼承IMyAidlInterface這個接口的。
public static abstract class Stub extends android.os.Binder implements com.example.newserver.IMyAidlInterface
來看看Service里面的這個實現類
IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {
@Override
public void addPerson(Person person) throws RemoteException {
if (null == mPersonArrayList) {
mPersonArrayList = new ArrayList<>();
}
mPersonArrayList.add(person);
}
@Override
public List<Person> getPersonList() throws RemoteException {
if (null != mPersonArrayList) {
return mPersonArrayList;
}
return null;
}
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
};
看到這里,終于就明白了吧,就是調用了Service里面的方法。
來寫一個總結流程:
1.首先客戶端先通過ServiceConnection獲取了服務端的定義的一個binder
2.拿到binder,然后通過一個代理類Proxy調用服務端定義的方法。服務端定義的方法就會執(zhí)行Transact方法
3.Transact方法又會執(zhí)行Binder類的的方法onTransact方法
4.onTrsact方法調用對應服務端的實現類IMyAidlInterface.Stub里面的方法。
我們看到,這其實就是binder在中間起到了連接的作用,實際上實現了binder就實現了跨進程通信的能力,中間就是Transact方法和onTransact的執(zhí)行。我們也完全可以通過這個步驟來脫離aidl文件來實現這個功能。
來看一下怎么實現。
1.首先客戶端先通過ServiceConnection獲取了服務端的定義的一個binder
ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
binder = MyProXy.getInstance(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
2.拿到binder,然后通過一個代理類Proxy調用服務端定義的方法。服務端定義的方法就會執(zhí)行Transact方法
這個代理類是在客戶端調用的。
public class MyProXy {
public static final int ADD = 0;
public static final int GET = 1;
private static IBinder mRemote;
private static MyProXy myProXy;
public MyProXy() {
}
public static MyProXy getInstance(IBinder binder) {
myProXy = new MyProXy();
mRemote = binder;
return myProXy;
}
/**
* 添加一個英雄
* @param person
*/
public void addPerson(Person person) {
Parcel _write = Parcel.obtain();
Parcel _reply = Parcel.obtain();
if (null != person) {
_write.writeInt(1);
person.writeToParcel(_write, 0);
} else {
_write.writeInt(0);
}
try {
mRemote.transact(ADD, _write, _reply, 0);
_reply.readException();
} catch (RemoteException e) {
e.printStackTrace();
}finally {
_write.recycle();
_reply.recycle();
}
}
/**
* 獲取英雄列表
* @return
*/
public List<Person> getPersonList(){
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
List<Person> mList = new ArrayList<>();
try {
mRemote.transact(GET,_data,_reply,0);
_reply.readException();
mList = _reply.createTypedArrayList(Person.CREATOR);
} catch (RemoteException e) {
e.printStackTrace();
}finally {
_data.recycle();
_reply.recycle();
}
return mList;
}
}
3.Transact方法又會執(zhí)行Binder類的的方法onTransact方法
這個類是寫在服務端的,里面有抽象方法,供Service的實現類實現
public abstract class Stub extends Binder {
public static final int ADD = 0;
public static final int GET = 1;
public abstract void addPerson(Person person);
public abstract List<Person> getPerson();
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code){
case ADD:
Person person;
if (0 != data.readInt()) {
person = Person.CREATOR.createFromParcel(data);
} else {
person = null;
}
this.addPerson(person);
reply.writeInt(1);
reply.writeNoException();
return true;
case GET:
List<Person> mList;
mList = this.getPerson();
reply.writeNoException();
reply.writeTypedList(mList);
return true;
default:
return super.onTransact(code, data, reply, flags);
}
}
}
4.onTrsact方法調用對應服務端的實現類IMyAidlInterface.Stub里面的方法
public class MyService extends Service {
private List<Person> mPersonList = new ArrayList<>();
Stub mStub = new Stub() {
@Override
public void addPerson(Person person) {
if (null == mPersonList) {
mPersonList = new ArrayList<>();
}
if (null != person) {
mPersonList.add(person);
}
}
@Override
public List<Person> getPerson() {
if (null != mPersonList) {
return mPersonList;
}
return null;
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mStub;
}
}
到這里就結束了,可以看到實現還是挺簡單的。
結語
Android中跨進程通信的方法還是挺多的,這兩篇只是講了其中aidl方式。

附上Demo傳送門~