Markdown版本筆記 | 個人GitHub首頁 | 個人博客 | 個人微信 | 個人郵箱 |
---|---|---|---|---|
MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
AIDL 定向tag IPC 案例 MDjava
Android官網上在講到AIDL的地方關於定向tag是這樣介紹的:android
All non-primitive parameters require a directional tag indicating which way the data goes. //全部的非基本數據類型的參數都須要一個定向tag來指出數據的流向
Either in , out , or inout. //能夠是 in , out ,或者 inout
Primitives are in by default , and connot be otherwise. //基本數據類型參數的定向tag默認是,而且只能是 ingit
AIDL中的定向 tag 表示了在跨進程通訊中數據的流向
,其中 in 表示數據只能由客戶端流向服務端
, out 表示數據只能由服務端流向客戶端
,而 inout 則表示數據可在服務端與客戶端之間雙向流通
。github
其中,數據流向是針對在客戶端中的那個傳入方法的對象而言的:微信
對象的完整數據
,可是客戶端的那個對象不會由於服務端對傳參的修改而發生變更;參數爲空的對象
,可是在服務端對接收到的空對象有任何修改以後客戶端將會同步變更
;而且
客戶端將會同步服務端對該對象的任何變更。public class Book implements Parcelable{}
package com.bqt.aidl; parcelable Book;
package com.bqt.aidl; import com.bqt.aidl.Book; interface BookManager { Book addBookIn(in Book book); Book addBookOut(out Book book); Book addBookInout(inout Book book); }
sourceSets { main { java.srcDirs = ['src/main/java', 'src/main/aidl'] } }
服務端的邏輯是,首先接受客戶端鏈接的請求,並把服務端處理好的BookManager.Stub
的IBinder接口回傳給客戶端。在BookManager.Stub實現的方法裏面,主要是接收客戶端傳過來的Book對象,並試圖對其進行修改,而後把修改過的對象再傳回去。源碼分析
public class AIDLService extends Service { @Override public IBinder onBind(Intent intent) { Log.i("bqt", "【Service-onBind】"); return new MyBind(); } private class MyBind extends BookManager.Stub { @Override public synchronized Book addBookIn(Book book) throws RemoteException { modifyBook(book, 100, "Service-In"); return book; } @Override public synchronized Book addBookOut(Book book) throws RemoteException { modifyBook(book, 200, "Service-Out"); return book; } @Override public synchronized Book addBookInout(Book book) throws RemoteException { modifyBook(book, 300, "Service-Inout"); return book; } private void modifyBook(Book book, int i, String s) { if (book != null) { Log.i("bqt", "【Service-接收到的Book】" + book); book.setPrice(i);//修改book,觀察客戶端的反饋 book.setName(s); Log.i("bqt", "【Service-返回的Book】" + book); } } } }
<!-- 聲明權限 --> <permission android:name="com.bqt.permission" android:protectionLevel="normal"/> <!-- 隱式服務 --> <service android:name=".AIDLService" android:permission="com.bqt.permission"> <intent-filter> <action android:name="com.bqt.service.aidl"/> </intent-filter> </service>
public class MainActivity extends ListActivity { private BookManager mBookManager; private MyServiceConnection mServiceConnection; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String[] array = { "addBookIn", "addBookOut", "addBookInout"}; setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, array)); mServiceConnection = new MyServiceConnection(); Intent intent = new Intent(); intent.setAction("com.bqt.service.aidl"); intent.setPackage("com.bqt.aidl2"); bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); if (mServiceConnection != null) { unbindService(mServiceConnection); } mBookManager = null; } @Override protected void onListItemClick(ListView l, View v, int position, long id) { if (mBookManager != null) { try { Book book = null, returnBook = null; switch (position) { case 0: book = new Book("客戶端-In", 10); Log.i("bqt", "【客戶端-傳進去的Book-執行前】" + book); returnBook = mBookManager.addBookIn(book); break; case 1: book = new Book("客戶端-Out", 20); Log.i("bqt", "【客戶端-傳進去的Book-執行前】" + book); returnBook = mBookManager.addBookOut(book); break; case 2: book = new Book("客戶端-Inout", 30); Log.i("bqt", "【客戶端-傳進去的Book-執行前】" + book); returnBook = mBookManager.addBookInout(book); break; } Log.i("bqt", "【客戶端-returnBook】" + returnBook); Log.i("bqt", "【客戶端-傳進去的Book-執行後】" + book); } catch (RemoteException e) { e.printStackTrace(); } } } private class MyServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { Toast.makeText(MainActivity.this, "服務已鏈接", Toast.LENGTH_SHORT).show(); mBookManager = BookManager.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { Toast.makeText(MainActivity.this, "服務已斷開", Toast.LENGTH_SHORT).show(); mBookManager = null; } } }
<!-- 聲明啓動服務所須要的權限 --> <uses-permission android:name="com.bqt.permission"/>
In測試
【客戶端-傳進去的Book-執行前】{name=客戶端-In,price=10} 【Service-接收到的Book】{name=客戶端-In,price=10} //收到了客戶端原始對象的值【in】 【Service-返回的Book】{name=Service-In,price=100} 【客戶端-returnBook】{name=Service-In,price=100} 【客戶端-傳進去的Book-執行後】{name=客戶端-In,price=10} //客戶端原始對象的值沒有改變
Outui
【客戶端-傳進去的Book-執行前】{name=客戶端-Out,price=20} 【Service-接收到的Book】{name=null,price=0} //沒有收到客戶端原始對象的值 【Service-返回的Book】{name=Service-Out,price=200} 【客戶端-returnBook】{name=Service-Out,price=200} 【客戶端-傳進去的Book-執行後】{name=Service-Out,price=200} //修改了客戶端原始對象的值【out】
InOutthis
【客戶端-傳進去的Book-執行前】{name=客戶端-Inout,price=30} 【Service-接收到的Book】{name=客戶端-Inout,price=30} //收到了客戶端原始對象的值【in】 【Service-返回的Book】{name=Service-Inout,price=300} 【客戶端-returnBook】{name=Service-Inout,price=300} 【客戶端-傳進去的Book-執行後】{name=Service-Inout,price=300} //修改了客戶端原始對象的值【out】
在 AIDL 文件生成的 java 文件中,在進行遠程調用的時候基本的調用順序是:
Proxy
類中調用對應的方法transact()
方法onTransact()
方法就會被調用業務邏輯
的方法private static class Proxy implements com.bqt.aidl.BookManager { 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 com.bqt.aidl.Book addBookIn(com.bqt.aidl.Book book) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); //表明從客戶端流向服務端的數據流 android.os.Parcel _reply = android.os.Parcel.obtain(); //表明從服務端流向客戶端的數據流 com.bqt.aidl.Book _result; //表明客戶端調用服務端方法後的返回值,返回值沒什麼可研究的 try { _data.writeInterfaceToken(DESCRIPTOR); if ((book != null)) { _data.writeInt(1); //若是book不爲空,則_data寫入int值1 book.writeToParcel(_data, 0); //將book中的數據寫入_data中(客戶端的數據被完整保留了起來) } else { _data.writeInt(0); //若是book爲空,則_data寫入int值0 } mRemote.transact(Stub.TRANSACTION_addBookIn, _data, _reply, 0); //間接調用onTransact方法 _reply.readException(); if ((0 != _reply.readInt())) { _result = com.bqt.aidl.Book.CREATOR.createFromParcel(_reply); } else { _result = null; } //能夠看到,在返回_result以前,沒有修改客戶端傳遞過來的book對象,因此客戶端原始對象不會被改變 } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public com.bqt.aidl.Book addBookOut(com.bqt.aidl.Book book) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); com.bqt.aidl.Book _result; try { _data.writeInterfaceToken(DESCRIPTOR); //能夠看到,這裏沒有將book對象寫入_data流就開始傳輸了,也即客戶端傳過來的數據內容被丟棄了 mRemote.transact(Stub.TRANSACTION_addBookOut, _data, _reply, 0); _reply.readException(); if ((0 != _reply.readInt())) { _result = com.bqt.aidl.Book.CREATOR.createFromParcel(_reply); } else { _result = null; } if ((0 != _reply.readInt())) { book.readFromParcel(_reply); //從_reply讀取數據而後寫入book中(客戶端的數據被改變了) //能夠看到,在返回_result以前,會修改客戶端傳遞過來的book對象,因此客戶端原始對象會被改變 } } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public com.bqt.aidl.Book addBookInout(com.bqt.aidl.Book book) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); com.bqt.aidl.Book _result; try { _data.writeInterfaceToken(DESCRIPTOR); if ((book != null)) { _data.writeInt(1); book.writeToParcel(_data, 0); //將book中的數據寫入_data中(客戶端的數據被完整保留了起來) } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addBookInout, _data, _reply, 0); _reply.readException(); if ((0 != _reply.readInt())) { _result = com.bqt.aidl.Book.CREATOR.createFromParcel(_reply); } else { _result = null; } if ((0 != _reply.readInt())) { book.readFromParcel(_reply);//從_reply讀取數據而後寫入book中(客戶端的數據被改變了) } } finally { _reply.recycle(); _data.recycle(); } return _result; } }
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { //data表明從客戶端流向服務端的數據流,reply表明從服務端流向客戶端的數據流 switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_addBookIn: { data.enforceInterface(DESCRIPTOR); com.bqt.aidl.Book _arg0; //_arg0表明客戶端輸入的book對象 if ((0 != data.readInt())) { _arg0 = com.bqt.aidl.Book.CREATOR.createFromParcel(data);//獲取客戶端輸入的book對象 } else { _arg0 = null; } com.bqt.aidl.Book _result = this.addBookIn(_arg0);//這裏纔是真正調用服務端寫好的實現的地方【代理】 //_result表明客戶端調用服務端方法後的返回值,返回值沒什麼可研究的 reply.writeNoException(); if ((_result != null)) { reply.writeInt(1); _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); //將返回值寫入reply } else { reply.writeInt(0); } //執行完方法以後就結束了,對_arg0的修改沒有同步到reply return true; } case TRANSACTION_addBookOut: { data.enforceInterface(DESCRIPTOR); com.bqt.aidl.Book _arg0; _arg0 = new com.bqt.aidl.Book(); //能夠看到,此時沒有從data裏讀取book對象的操做,而是直接new了一個book對象,這就是爲何服務端收不到客戶端傳過來的數據 com.bqt.aidl.Book _result = this.addBookOut(_arg0);//【代理】 reply.writeNoException(); if ((_result != null)) { reply.writeInt(1); _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); //將返回值寫入reply } else { reply.writeInt(0); } //將_arg0寫入reply中 if ((_arg0 != null)) { reply.writeInt(1); _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);//同步_arg0 } else { reply.writeInt(0); } return true; } case TRANSACTION_addBookInout: { data.enforceInterface(DESCRIPTOR); com.bqt.aidl.Book _arg0; if ((0 != data.readInt())) { _arg0 = com.bqt.aidl.Book.CREATOR.createFromParcel(data);//獲取客戶端輸入的book對象 } else { _arg0 = null; } com.bqt.aidl.Book _result = this.addBookInout(_arg0);//【代理】 reply.writeNoException(); if ((_result != null)) { reply.writeInt(1); _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } if ((_arg0 != null)) { reply.writeInt(1); _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);//同步_arg0 } else { reply.writeInt(0); } return true; } } return super.onTransact(code, data, reply, flags); }
2017-11-2