Android IPC系列(一):AIDL使用详解
概述
AIDL可以實現(xiàn)進程間的通信,由于每個進程都是運行在獨立的空間,不同的進程想要交互需要借助一些特殊的方式,AIDL就是其中的一種,AIDL是一種模板,因為實際交互過程中,并不是AIDL起的作用,具體會在之后源碼分析解釋,AIDL的作用是為了避免重復編寫代碼而出現(xiàn)的一個模板
語法
AIDL的語法十分簡單,與Java語言基本保持一致,需要記住的規(guī)則有以下幾點:
-
AIDL文件以 .aidl 為后綴名 AIDL支持的數(shù)據(jù)類型分為如下幾種:
- 八種基本數(shù)據(jù)類型:byte、char、int、long、float、double、boolean String,CharSequence,其中不支持short類型
- 實現(xiàn)了Parcelable接口的數(shù)據(jù)類型
- List 類型。List承載的數(shù)據(jù)必須是AIDL支持的類型,或者是其它聲明的AIDL對象
- Map類型。Map承載的數(shù)據(jù)必須是AIDL支持的類型,或者是其它聲明的AIDL對象
-
定向Tag。定向Tag表示在跨進程通信中數(shù)據(jù)的流向,用于標注方法的參數(shù)值,分為 in、out、inout 三種。其中
- in 表示數(shù)據(jù)只能由客戶端流向服務端
- out 表示數(shù)據(jù)只能由服務端流向客戶端
- inout 則表示數(shù)據(jù)可在服務端與客戶端之間雙向流通
- 此外,如果AIDL方法接口的參數(shù)值類型是:基本數(shù)據(jù)類型、String、CharSequence或者其他AIDL文件定義的方法接口,那么這些參數(shù)值的定向 Tag 默認是且只能是 in,所以除了這些類型外,其他參數(shù)值都需要明確標注使用哪種定向Tag。定向Tag具體的使用差別后邊會有介紹
-
明確導包。在AIDL文件中需要明確標明引用到的數(shù)據(jù)類型所在的包名,即使兩個文件處在同個包名下
服務端
- 先建立一個項目
- 由于要傳輸自定義User對象,所以定義一個User的aidl文件,直接生成 創(chuàng)建完成后,系統(tǒng)就會默認創(chuàng)建一個 aidl 文件夾,文件夾下的目錄結構即是工程的包名,Book.aidi 文件就在其中 然后更改User.aidl文件內(nèi)容
- 然后生成一個User的類,實現(xiàn)Parcelable
- 然后在定義一個BookName的aidl文件,向客戶端暴露可調(diào)用的接口,需要手動導入User,import com.baidu.bpit.aibaidu.aidl.User;
- 這時候重新build一下工程
- 現(xiàn)在需要來創(chuàng)建一個 Service 供客戶端遠程綁定了,返回你的自定義的Binder
- AndroidManifest.xml文件定義
客戶端
- 首先把服務端的aidl文件夾,整體復制到客戶端
- 之后,需要創(chuàng)建和服務端User類所在的相同包名來存放 User類
- 在MainActivity綁定服務端的service,點擊按鈕獲取書名
- 點擊按鈕打印
正確獲取數(shù)據(jù)
定向TAG
有三種定向TAG
- inout:服務端修改數(shù)據(jù),會同步到客戶端,因此可以說數(shù)據(jù)是雙向流動的
- in:數(shù)據(jù)只從客戶端流向服務端,服務端修改數(shù)據(jù)不會影響客戶端
- out:數(shù)據(jù)只能由服務端傳向客戶端,及時客戶端傳入一個對象,這個對象也是空的,即沒有數(shù)據(jù),服務端獲取該對象后,對該對象任何操作都會同步到客戶端這里
修改aidl
interface BookName {String getName();List<User> getList();void addInout(inout User user);void addIn(in User user);void addout(out User user);} 復制代碼這次增加了三個方法addInout,addIn,addout,之后分別測試這三個方法
修改User類 User類需要添加倆個方法,一個無參構造,一個readFromParcel
public class User implements Parcelable {public String name;public User(){}public User(String name){this.name=name;}protected User(Parcel in) {name = in.readString();}public static final Creator<User> CREATOR = new Creator<User>() {@Overridepublic User createFromParcel(Parcel in) {return new User(in);}@Overridepublic User[] newArray(int size) {return new User[size];}};@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(name);}public void readFromParcel(Parcel dest) {name = dest.readString();} } 復制代碼先測試一下inout
服務端
public class ServiceService extends Service {public ServiceService() {}@Overridepublic IBinder onBind(Intent intent) {return new MyBinder();}class MyBinder extends BookName.Stub {@Overridepublic String getName() throws RemoteException {return "西游記";}@Overridepublic List<User> getList() throws RemoteException {User user = new User("111");User user1 = new User("222");List<User> users = new ArrayList<>();users.add(user1);users.add(user);return users;}@Overridepublic void addInout(User user) throws RemoteException {Log.d("mmmserver","服務端獲取到:"+user.name);user.name="服務端更改";Log.d("mmmserver","服務端修改書名:"+user.name);}@Overridepublic void addIn(User user) throws RemoteException {}@Overridepublic void addout(User user) throws RemoteException {}} } 復制代碼主要看inout方法,服務端接受到客戶端傳來的信息后,修改信息內(nèi)容
客戶端
private void initView() {findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {User user = new User("客戶端傳入");Log.d("mmmclient", "客戶端向服務端傳入一本書,書名:" + user.name);bookName.addInout(user);Log.d("mmmclient", "服務端修改書名后,書名:" + user.name);} catch (RemoteException e) {e.printStackTrace();}}});} 復制代碼點擊按鈕后,向服務端傳入數(shù)據(jù),服務端收到數(shù)據(jù),會對數(shù)據(jù)更改,客戶端再次查看此數(shù)據(jù),看是否同步
01-18 23:15:18.529 5606-5606/com.baidu.bpit.aibaidu.client D/mmmclient: 客戶端向服務端傳入一本書,書名:客戶端傳入 01-18 23:15:18.529 5527-5554/com.baidu.bpit.aibaidu.aidl D/mmmserver: 服務端獲取到:客戶端傳入 01-18 23:15:18.530 5527-5554/com.baidu.bpit.aibaidu.aidl D/mmmserver: 服務端修改書名:服務端更改 01-18 23:15:18.530 5606-5606/com.baidu.bpit.aibaidu.client D/mmmclient: 服務端修改書名后,書名:服務端更改 復制代碼看到服務端修改可以及時同步到客戶端,這就是inout 數(shù)據(jù)雙向流動
測試in
服務端
@Overridepublic void addIn(User user) throws RemoteException {Log.d("mmmserverIn", "服務端獲取到:" + user.name);user.name = "服務端更改";Log.d("mmmserverIn", "服務端修改書名:" + user.name);} 復制代碼客戶端
private void initView() {findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {User user = new User("客戶端傳入");Log.d("mmmclient", "客戶端向服務端傳入一本書,書名:" + user.name);bookName.addIn(user);Log.d("mmmclient", "服務端修改書名后,書名:" + user.name);} catch (RemoteException e) {e.printStackTrace();}}});} 復制代碼當點擊按鈕,會發(fā)送數(shù)據(jù)到服務端,服務端會更改數(shù)據(jù)內(nèi)容,客戶端再次查看數(shù)據(jù),看是否被改變
01-18 23:26:23.079 5815-5815/com.baidu.bpit.aibaidu.client D/mmmclient: 客戶端向服務端傳入一本書,書名:客戶端傳入 01-18 23:26:23.080 5736-5763/com.baidu.bpit.aibaidu.aidl D/mmmserverIn: 服務端獲取到:客戶端傳入 01-18 23:26:23.081 5736-5763/com.baidu.bpit.aibaidu.aidl D/mmmserverIn: 服務端修改書名:服務端更改 01-18 23:26:23.081 5815-5815/com.baidu.bpit.aibaidu.client D/mmmclient: 服務端修改書名后,書名:客戶端傳入 復制代碼看以看出服務端修改數(shù)據(jù),并不會影響客戶端
測試OUT
服務端
@Overridepublic void addout(User user) throws RemoteException {Log.d("mmmserverout", "服務端獲取到:" + user.name);user.name = "服務端更改";Log.d("mmmserverout", "服務端修改書名:" + user.name);} 復制代碼客戶端
private void initView() {findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {User user = new User("客戶端傳入");Log.d("mmmclient", "客戶端向服務端傳入一本書,書名:" + user.name);bookName.addout(user);Log.d("mmmclient", "服務端修改書名后,書名:" + user.name);} catch (RemoteException e) {e.printStackTrace();}}});} 復制代碼客戶端向服務端傳入數(shù)據(jù),服務端收到后,更改數(shù)據(jù),客戶端再次查看數(shù)據(jù)
01-18 23:36:21.997 6100-6100/com.baidu.bpit.aibaidu.client D/mmmclient: 客戶端向服務端傳入一本書,書名:客戶端傳入 01-18 23:36:21.998 6023-6037/com.baidu.bpit.aibaidu.aidl D/mmmserverout: 服務端獲取到:null服務端修改書名:服務端更改 01-18 23:36:21.998 6100-6100/com.baidu.bpit.aibaidu.client D/mmmclient: 服務端修改書名后,書名:服務端更改 復制代碼可以看到服務端收到的是空對象,服務端更改影響客戶端
GitHub: 參考:www.jianshu.com/p/29999c1a9…
轉(zhuǎn)載于:https://juejin.im/post/5d4d12e7518825237b5bdb4d
總結
以上是生活随笔為你收集整理的Android IPC系列(一):AIDL使用详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Cause: com.ibatis.co
- 下一篇: Spring实战(前言:Spring容器