理解AIDL中的in,out,inout
最後一次更新:2018-3-25
- android測試版本:Android O
- 內容:驗證Android AIDL中的tag(in out inout)
前言
android AIDL有3種不同的tag,在總結之前先參考了這篇部落格 https://blog.csdn.net/luoyanglizi/article/details/51958091
但是發現還是不夠,於是又自己研究了一下,總結出這篇文件。如果有錯誤的話希望指正。
驗證
IPostMsg.aidl
package aidl;
import aidl.MsgBody;
interface IPostMsg {
void setMsg(String msg);
//(1)沒有宣告out能返回嗎? == 能
MsgBody getMsg1();
//(2)out 不能傳入,服務端能修改客戶端的b引數
MsgBody getMsg2(out MsgBody b);
//(3)in 能傳入,服務端不能修改客戶端的b引數
MsgBody getMsg3(in MsgBody b);
//(4)inout 能傳入,服務端能修改客戶端的b引數
MsgBody getMsg4(inout MsgBody b);
}
MsgBody.aidl
package aidl;
parcelable MsgBody;
package aidl;
import android.os.Parcel;
import android.os.Parcelable;
public class MsgBody implements Parcelable {
public String msgContext;
public int msgId;
public MsgBody() {}
protected MsgBody(Parcel in) {
readFromParcel(in);
}
public static final Creator<MsgBody> CREATOR = new Creator<MsgBody>() {
@Override
public MsgBody createFromParcel(Parcel in) {
return new MsgBody(in);
}
@Override
public MsgBody[] newArray(int size) {
return new MsgBody[size];
}
};
@Override
public int describeContents() {
return 0;
}
/**
* @param dest
* @param flags flags=PARCELABLE_WRITE_RETURN_VALUE:表示該物件從服務端返回客戶端
* flags=PARCELABLE_ELIDE_DUPLICATES 程式內部複製變數的時候
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(msgContext);
dest.writeInt(msgId);
}
public void readFromParcel(Parcel in) {
msgContext = in.readString();
msgId = in.readInt();
}
@Override
public String toString() {
return "id = " + msgId + " msgContext = " + msgContext;
}
}
上面定義了MsgBody.aidl,IPostMsg.aidl,
值得注意的是:
1. MsgBody.aidl,IPostMsg.aidl即使在一個包下,IPostMsg.aidl中引用MsgBody時,也要寫import aidl.MsgBody;
2. public MsgBody() {}必須有一個空的構造方法,否則使用out tag的時候會報錯。
Error:(72, 9) 錯誤: 無法將類 MsgBody中的構造器 MsgBody應用到給定型別;
需要: Parcel
找到: 沒有引數
原因: 實際引數列表和形式引數列表長度不同
- ,使用out tag序列化的時候一定要有下面的函式
public void readFromParcel(Parcel in) {
msgContext = in.readString();
msgId = in.readInt();
}
否則會報
Error:(215, 2) 錯誤: 找不到符號
符號: 方法 readFromParcel(Parcel)
位置: 型別為MsgBody的變數 b
現在客服務都開啟服務,客戶端獲取
測試MsgBody getMsg1();
客戶端先setMsg(String msg)
服務端用getMsg1()返回MsgBody
客戶端
log("setMsg = " + outStr);
postMsg.setMsg(outStr);
MsgBody b = postMsg.getMsg1();
log("getMsg1 " + b.toString());
服務端
private String msg;
@Override
public void setMsg(String msg) throws RemoteException {
log("server get " + msg);
this.msg = msg;
}
@Override
public MsgBody getMsg1() throws RemoteException {
MsgBody msgBody = new MsgBody();
int id = 10;
msgBody.msgId = id;
msgBody.msgContext = msg;
log("out getMsg " + msgBody.toString());
return msgBody;
}
輸出log
01-01 19:16:58.602 30532-30532/com.example.root.aidlclient I/wangcan: client setMsg = dffff
01-01 19:16:58.604 30263-30281/com.example.root.aidlservice:remote I/wangcan: service server get dffff
01-01 19:16:58.612 30263-30281/com.example.root.aidlservice:remote I/wangcan: service out getMsg id = 10 msgContext = dffff
01-01 19:16:58.616 30532-30532/com.example.root.aidlclient I/wangcan: client getMsg1 id = 10 msgContext = dffff
結論:直接retrun 返回不需要什麼tag,跟一般java函式呼叫沒有區別
MsgBody getMsg2(out MsgBody b);
客戶端
//測試getMsg2
log("測試getMsg2");
MsgBody test = new MsgBody();
test.msgId = 999;
test.msgContext = "test";
log("傳入" + test.toString());
MsgBody r1 = postMsg.getMsg2(test);
log(test.toString());
服務端
public MsgBody getMsg2(MsgBody b) throws RemoteException {
log("getMsg2 接收" + b.toString());
b.msgId=222;
b.msgContext="change";
log("getMsg2 修改"+ b.toString());
return null;
}
輸出log
01-01 19:16:58.617 30532-30532/com.example.root.aidlclient I/wangcan: client 傳入id = 999 msgContext = test
01-01 19:16:58.618 30263-30281/com.example.root.aidlservice:remote I/wangcan: service getMsg2 接收id = 0 msgContext = null
01-01 19:16:58.619 30263-30281/com.example.root.aidlservice:remote I/wangcan: service getMsg2 修改id = 222 msgContext = change
01-01 19:16:58.622 30532-30532/com.example.root.aidlclient I/wangcan: client id = 222 msgContext = change
結論:
如果使用out tag用於入參
1. service getMsg2 接收id = 0 msgContext = null 說明,服務端不能得到傳入的資料
2. 在服務端修改值(service getMsg2 修改id = 222 msgContext = change),這個值被修改了
服務端能修改客戶端的入引數據,但不能獲取這個引數資料
MsgBody getMsg3(in MsgBody b);
客戶端與服務端程式碼與getMsg2一樣,直接看log
01-01 19:16:58.623 30532-30532/com.example.root.aidlclient I/wangcan: client 傳入id = 999 msgContext = test
01-01 19:16:58.624 30263-30281/com.example.root.aidlservice:remote I/wangcan: service getMsg3 接收id = 999 msgContext = test
01-01 19:16:58.625 30263-30281/com.example.root.aidlservice:remote I/wangcan: service getMsg3 修改id = 333 msgContext = change
01-01 19:16:58.627 30532-30532/com.example.root.aidlclient I/wangcan: client id = 999 msgContext = test
結論:
如果使用in tag用於入參
1. service getMsg3 接收service getMsg3 接收id = 999 msgContext = test 說明,服務端能得到傳入的資料
2. 在服務端修改值(service getMsg2 修改id = 333 msgContext = change),但是服務端的值沒有改變,仍然是(client id = 999 msgContext = test)
服務端不能修改客戶端的入引數據,但能獲取這個引數資料
MsgBody getMsg4(inout MsgBody b);
客戶端與服務端程式碼與上面兩個一樣,直接看log
01-01 19:16:58.628 30532-30532/com.example.root.aidlclient I/wangcan: client 傳入id = 999 msgContext = test
01-01 19:16:58.629 30263-30281/com.example.root.aidlservice:remote I/wangcan: service getMsg4 接收id = 999 msgContext = test
01-01 19:16:58.630 30263-30281/com.example.root.aidlservice:remote I/wangcan: service getMsg4 修改id = 444 msgContext = change
01-01 19:16:58.632 30532-30532/com.example.root.aidlclient I/wangcan: client id = 444 msgContext = change
如果使用inout tag用於入參
1. “接收id = 999 msgContext = test” 說明,服務端能得到傳入的資料
2. 在服務端修改值(service getMsg2 修改id = 333 msgContext = change),與後面客戶端對應的引數的值(client id = 444 msgContext = change)
3. 最後retrun 返回跟getMsg1一樣
服務端能修改客戶端的入引數據,也能獲取這個引數資料
最後的結論
- 即使在一個包裡面也要匯入包名
- MsgBody getMsg();可以直接返回,不需要什麼tag
- MsgBody getMsg2(out MsgBody b); 服務端能修改客戶端的入引數據,但不能獲取這個引數資料
- MsgBody getMsg3(in MsgBody b); 服務端不能修改客戶端的入引數據,但能獲取這個引數資料
- MsgBody getMsg4(inout MsgBody b);服務端能修改客戶端的入引數據,也能獲取這個引數資料
- tag (in out inout)是相對與服務端說的,in就是資料能進入客戶端,out是資料能出服務端,inout是能進能出
- 使用out tag序列化的時候一定要有下面的函式和無參建構函式。aidl最後會編譯出對應的java檔案。如果使用的out tag,原始碼中使用這兩個方法。
public void readFromParcel(Parcel in) {
msgContext = in.readString();
msgId = in.readInt();
}
我的測試程式碼:
https://gitee.com/namedcan/WangCanAIDL或直接git clone [email protected]:namedcan/WangCanAIDL.git