AIDL簡介
在Android
中,進程之間原則上是不能進行通信的。但偏偏Android
從四大組件到框架、底層到處都是IPC的影子。AIDL
就是IPC
方式之一。
AIDL
(Android
接口定義語言) 是 Android
提供的一種進程間通信 (IPC
) 機制。
我們可以使用它在兩個不同進程之間的Client
與Server
進行通信。
使用AIDL步驟
使用aidl
大致分為三塊,編寫aidl
生成必要文件。創建Client
和Server
使用。
- 編寫
AIDL
- 創建
Bean
類,實現Parcelable
接口(便于序列化、反序列化)。 - 編寫
aidl
文件 - 生成
java
文件
- 創建
- 編寫
Server
- 創建
Service
,在其中創建上面生成的Binder
對象實例,實現接口定義的方法 - 在
onBind()
中返回
- 創建
- 編寫
Client
- 實現
ServiceConnection
接口,在其中拿到AIDL
類 - 綁定服務
- 調用
aidl
中的請求并等待返回結果
- 實現
步驟一:編寫AIDL
- 創建
Bean
類,實現Parcelable
接口(便于序列化、反序列化)
package com.cx.aidldemo.bean;
import android.os.Parcel;
import android.os.Parcelable;
/**
* 書的實體類
*/
public class Book implements Parcelable {
private String name;
private double price;
public Book() {}
public Book(String name, double price) {
this.name = name;
this.price = price;
}
protected Book(Parcel in) {
name = in.readString();
price = in.readDouble();
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeDouble(price);
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
-
編寫
aidl
文件- 不過在編寫aidl文件之前,要擁有
aidl
目錄。沒有的話就創建。 - 創建方式:在
main
目錄下創建aidl
目錄,并在aidl
目錄下創建和java
目錄下子目錄一樣的包名。
- 不過在編寫aidl文件之前,要擁有
aidl包名一致.png
- 創建Bean類的aidl
// Book.aidl
package com.cx.aidldemo.bean;
parcelable Book;
- 創建接口的aidl
// IMyService.aidl
package com.cx.aidldemo;
import com.cx.aidldemo.bean.Book;
interface IMyService {
/**
* 添加一個書
*/
void addBook(in Book book);
/**
* 獲取所有書
*/
List<Book> getBookList();
}
?
注意:
- 這個
Book.aidl
的包名要和實體類包名一致。- 除了基本數據類型,其他類型的參數都需要標上方向類型:in(輸入),out(輸出),inout(輸入輸出)。
- 非基本類型的數據需要導入它的全路徑。即便是同級目錄下。
- 生成
java
文件- 方式:
Build -> Make Project
- 然后就會在
app/build/generated/source/aidl/package_name/
下生成一個Java
文件
- 方式:
生成java文件.png
現在我們就可以通過它來進行IPC通信了。
步驟二:編寫Server
- 創建
Service
,在其中創建上面生成的Binder
對象實例,實現接口定義的方法 - 在
onBind()
中返回
public class MyAIDLService extends Service {
private List<Book> books;
public MyAIDLService() {
}
private IBinder mIBinder = new IMyService.Stub() {
@Override
public void addBook(Book book) throws RemoteException {
books.add(book);
}
@Override
public List<Book> getBookList() throws RemoteException {
return books;
}
};
@Override
public IBinder onBind(Intent intent) {
books = new ArrayList<Book>();
return mIBinder;
}
}
配置清單:
<service
android:name=".MyAIDLService"
android:enabled="true"
android:exported="true"
android:process=":aidl"></service>
-
enabled屬性
- 默認為
true
- 其值為
true
,則說明應用程序組件可以被Android
系統自動實例化 - 如果為
false
,則說明實例化組件的工作需要手工完成。
- 默認為
-
exported屬性
- 是否支持其它應用調用當前組件
- 如果包含有
intent-filter
默認值為true
;沒有intent-filter
默認值為false
-
process屬性
- 如果該屬性里設置的名字以冒號開頭(:),那么在需要的時候它將生成該應用程序的一個私有新進程。
服務端實現了接口,在 onBind()
中返回這個 Binder,客戶端拿到就可以操作數據了。
步驟三:編寫Client
- 實現
ServiceConnection
接口,在其中拿到AIDL
類
public class MainActivity extends AppCompatActivity {
private IMyService iMyService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
// onBind連接后會返回 Binder,也就是iBinder參數
// 將其轉換成 AIDL,在不同進程會返回代理對象
iMyService = IMyService.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
iMyService = null;
}
};
}
- 綁定服務
Intent intent1 = new Intent(getApplicationContext(), MyAIDLService.class);
// 綁定服務
bindService(intent1, connection, BIND_AUTO_CREATE);
- 調用
aidl
中的請求并等待返回結果
/**
* 添加一本書
* @param view
*/
public void onAddBook(View view) {
Book book = new Book("Android_" + System.currentTimeMillis(), 100);
try {
iMyService.addBook(book);
} catch (RemoteException e) {
e.printStackTrace();
}
}
/**
* 獲取所有書籍
* @param view
*/
public void onGetBooks(View view) {
try {
tvResult.setText(iMyService.getBookList().toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
日志打印:
服務端進程名.png
客戶端進程名.png
運行結果:
運行結果.gif