天天看點

【Android】程序間通信IPC——AIDL

AIDL

官網定義

AIDL(Android 接口定義語言)與您可能使用過的其他 IDL 類似。 您可以利用它定義用戶端與服務使用程序間通信 (IPC) 進行互相通信時都認可的程式設計接口。 在 Android 上,一個程序通常無法通路另一個程序的記憶體。 盡管如此,程序需要将其對象分解成作業系統能夠識别的原語,并将對象編組成跨越邊界的對象。 編寫執行這一編組操作的代碼是一項繁瑣的工作,是以 Android 會使用 AIDL 來處理。

支援類型

Java基本資料類型(int,long,char,boolean,float,double等);

CharSequence,String

實作Parcelable的對象

List和Map(元素必須是以上支援的資料類型,生成方法使用List和Map,接受端實際類型為ArrayList和HashMap)

實作

實作Parcelable實體

要傳遞的實體類UserBean

public class UserBean implements Parcelable {

private String name;

private int age;

private String address;

public UserBean() {

}

public UserBean(String name, int age, String address) {

this.name = name;

this.age = age;

this.address = address;

public String getName() {

return name;

public void setName(String name) {

public int getAge() {

return age;

public void setAge(int age) {

public String getAddress() {

return address;

public void setAddress(String address) {

protected UserBean(Parcel in) {

name = in.readString();

age = in.readInt();

address = in.readString();

public static final Creator<UserBean> CREATOR = new Creator<UserBean>() {

@Override

public UserBean createFromParcel(Parcel in) {

return new UserBean(in);

public UserBean[] newArray(int size) {

return new UserBean[size];

};

public int describeContents() {

return 0;

public void writeToParcel(Parcel dest, int flags) {

dest.writeString(name);

dest.writeInt(age);

dest.writeString(address);

/**

* 需要手動添加,Android Studio沒法直接生成

*/

public void readFromParcel(Parcel reply) {

name = reply.readString();

age = reply.readInt();

address = reply.readString();

public String toString() {

return "UserBean{" +

"name='" + name + '\'' +

", age=" + age +

", address='" + address + '\'' +

'}';

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

注: Android Studio中實作Parcelable設定完屬性就能快速生成必要的代碼,但是readFromParcel方法需要手動實作,否則無法編譯通過會報錯

Process 'command 'D:\software\android\sdk\build-tools\28.0.3\aidl.exe'' finished with non-zero exit value 1

AIDL檔案

映射對象

// UserBean.aidl

package com.sjl.exercise.bean;

// Declare any non-default types here with import statements

parcelable UserBean;

接口aidl

注:

import聲明任何非預設類型(例 UserBean)

方法中除了基本資料類型,其他類型的需要标上方向類型(in,out,inout)

// ICustomAidlInterface.aidl

package com.sjl.exercise;

import com.sjl.exercise.bean.UserBean;

interface ICustomAidlInterface {

String getCurrentTime();

void insertUser(in UserBean userBean);

List<UserBean> getUsers();

void clearUser();

定義完成後Make Project一下等待建構完成

服務端

建立遠端服務

public class RemoteService extends Service {

private static final String TAG = "RemoteService";

private List<UserBean> list = new ArrayList<>();

ICustomAidlInterface.Stub stub = new ICustomAidlInterface.Stub() {

public String getCurrentTime() throws RemoteException {

return new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date());

public void insertUser(UserBean userBean) throws RemoteException {

list.add(userBean);

public List<UserBean> getUsers() throws RemoteException {

return list;

public void clearUser() throws RemoteException {

list.clear();

public void onCreate() {

super.onCreate();

Log.i(TAG, "onCreate");

Toast.makeText(this, "遠端服務onCreate", Toast.LENGTH_SHORT).show();

* 傳回IBinder用于通信

* @param intent

* @return

public IBinder onBind(Intent intent) {

Log.i(TAG, "onBind");

Toast.makeText(this, "遠端服務onBind", Toast.LENGTH_SHORT).show();

return stub;

public boolean onUnbind(Intent intent) {

Log.i(TAG, "onUnbind");

Toast.makeText(this, "遠端服務onUnbind", Toast.LENGTH_SHORT).show();

return super.onUnbind(intent);

public void onDestroy() {

Log.i(TAG, "onDestroy");

Toast.makeText(this, "遠端服務onDestroy", Toast.LENGTH_SHORT).show();

super.onDestroy();

AndroidManifest.xml配置服務,定義Action用于隐式喚醒

<service

android:name=".module.service.remote.RemoteService"

android:enabled="true"

android:exported="true"

android:process=":remote">

<intent-filter>

<action android:name="com.sjl.aidl.remote" />

</intent-filter>

</service>

用戶端

拷貝服務端的aidl檔案及自定義的UserBean對象放到用戶端的中,路徑需要與服務端保持一緻

綁定服務

Intent intent = new Intent();

//AndroidManifest.xml中定義的伺服器端Action

intent.setAction("com.sjl.aidl.remote");

//5.0後無法通過隐式Intent綁定遠端Service,需設定包名

intent.setPackage("com.sjl.exercise");

bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);

擷取到AIDL接口

private ICustomAidlInterface iCustomAidlInterface;

private ServiceConnection serviceConnection = new ServiceConnection() {

public void onServiceConnected(ComponentName name, IBinder service) {

iCustomAidlInterface = ICustomAidlInterface.Stub.asInterface(service);

Log.i(TAG, "onServiceConnected");

Toast.makeText(MainActivity.this, "service connected", Toast.LENGTH_SHORT).show();

public void onServiceDisconnected(ComponentName name) {

Log.i(TAG, "onServiceDisconnected");

iCustomAidlInterface = null;

調用AIDL接口

iCustomAidlInterface.getCurrentTime();

UserBean userBean = new UserBean();

userBean.setName("name" + cnt);

userBean.setAddress("address" + cnt);

userBean.setAge(cnt);

iCustomAidlInterface.insertUser(userBean);

iCustomAidlInterface.getUsers();

iCustomAidlInterface.clearUser();

UserBean

---------------------