Android IPC机制之AIDL

什么是AIDL

AIDL:Android Interface Definition Language,即Android接口定义语言。

Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信。
为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现。
与很多其他的基于RPC的解决方案一样,Android使用一种接口定义语言(Interface Definition Language,IDL)来公开服务的接口。
我们知道4个Android应用程序组件中的3个(Activity、BroadcastReceiver和ContentProvider)都可以进行跨进程访问,
另外一个Android应用程序组件Service同样可以。因此,可以将这种可以跨进程访问的服务称为AIDL(Android Interface Definition Language)服务。
 
下面用两个例子来说一下AIDL在Android中的用法:
 
一 AIDL的简单用法
两个进程,客户端调用服务端的方法
实现步骤:

服务端:
1、创建一个AIDL文件,实际上是一个interface,声明一个方法
2、创建一个服务,利用AIDL文件的Stub方法在服务中实例化AIDL文件,实现AIDL文件中接口中定义的方法,返回一个IBinder对象
3、当绑定服务时将这个IBinder对象返回

客户端:
1、创建一个和服务端一模一样的AIDL文件,声明同样的方法
2、绑定服务,得到服务端返回的IBinder对象
3、将IBinder对象转换为本地定义AIDL文件,实际上是一个已经实例化的AIDL对象
4、用这个AIDL对象就可以调用服务端的方法

 

服务端的代码:

首先在Android Studio中创建一个aidl文件,Android Studio会自动创建一个aidl的文件夹:

 

 

创建一个aidl文件 IMyAdd,其中定义个简单的加法运算:

 1 // IMyAdd.aidl
 2 package com.jiao.myaidl;
 3 
 4 // Declare any non-default types here with import statements
 5 
 6 interface IMyAdd {
 7     /**
 8      * Demonstrates some basic types that you can use as parameters
 9      * and return values in AIDL.
10      */
11     int add(int first,int second);
12 }

然后创建一个service

 1 package com.jiao.myaidl;
 2 
 3 import android.app.Service;
 4 import android.content.Intent;
 5 import android.os.Binder;
 6 import android.os.IBinder;
 7 import android.os.RemoteException;
 8 import android.support.annotation.Nullable;
 9 
10 /**
11  * Created by jiaocg on 2016/3/9.
12  */
13 public class MyAddService extends Service {
14 
15 
16     public MyAddService() {
17     }
18 
19 
20     private Binder mBinder = new IMyAdd.Stub() {
21         @Override
22         public int add(int first, int second) throws RemoteException {
23             return first + second;
24         }
25     };
26 
27     @Nullable
28     @Override
29     public IBinder onBind(Intent intent) {
30         return mBinder;
31     }
32 }

 

在清单文件中注册service

1  <service android:name="com.jiao.myaidl.MyAddService">
2             <intent-filter>
3                 <action android:name="com.jiao.myaidl.action.MYADD_SERVICE" />
4 
5                 <category android:name="android.intent.category.DEFAULT" />
6             </intent-filter>
7         </service>

 

客户端代码

和服务端一样首先创建同样的aidl文件,并且声明同样的方法(注意,一定要在同一个包名下)

创建aidl文件:

 1 // IMyAdd.aidl
 2 package com.jiao.myaidl;
 3 
 4 // Declare any non-default types here with import statements
 5 
 6 interface IMyAdd {
 7     /**
 8      * Demonstrates some basic types that you can use as parameters
 9      * and return values in AIDL.
10      */
11     int add(int first,int second);
12 }

客户端调用代码:

  1 package com.jiao.myaidl;
  2 
  3 import android.content.ComponentName;
  4 import android.content.Context;
  5 import android.content.Intent;
  6 import android.content.ServiceConnection;
  7 import android.os.Bundle;
  8 import android.os.IBinder;
  9 import android.os.RemoteException;
 10 import android.support.v7.app.AppCompatActivity;
 11 import android.view.View;
 12 import android.widget.Button;
 13 import android.widget.Toast;
 14 
 15 import com.jiao.myaidl.client.R;
 16 
 17 public class MainActivity extends AppCompatActivity implements View.OnClickListener {
 18 
 19     private boolean mIsBindService;
 20     private IMyAdd mIMyAdd;
 21     private ServiceConnection mConnection = new ServiceConnection() {
 22         @Override
 23         public void onServiceConnected(ComponentName name, IBinder service) {
 24 
 25             Toast.makeText(MainActivity.this, "绑定服务成功", Toast.LENGTH_SHORT).show();
 26             mIMyAdd = IMyAdd.Stub.asInterface(service);
 27         }
 28 
 29         @Override
 30         public void onServiceDisconnected(ComponentName name) {
 31 
 32             bindService();
 33         }
 34     };
 35     private Button bt_aidl_add;
 36     private Button bt_aidl_bind;
 37     private Button bt_aidl_unbind;
 38 
 39     @Override
 40     protected void onCreate(Bundle savedInstanceState) {
 41         super.onCreate(savedInstanceState);
 42         setContentView(R.layout.activity_main);
 43 
 44         initView();
 45 
 46     }
 47 
 48     private void initView() {
 49 
 50         bt_aidl_bind = (Button) findViewById(R.id.bt_aidl_bind);
 51         bt_aidl_unbind = (Button) findViewById(R.id.bt_aidl_unbind);
 52         bt_aidl_add = (Button) findViewById(R.id.bt_aidl_add);
 53         bt_aidl_add.setOnClickListener(this);
 54         bt_aidl_bind.setOnClickListener(this);
 55         bt_aidl_unbind.setOnClickListener(this);
 56     }
 57 
 58 
 59     //绑定服务
 60     private void bindService() {
 61         Intent intent = new Intent();
 62         intent.setAction("com.jiao.myaidl.action.MYADD_SERVICE");
 63         bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
 64         mIsBindService = true;
 65     }
 66 
 67 
 68     //解绑服务
 69     private void unbindService() {
 70 
 71         if (mIsBindService) {
 72             mIsBindService = false;
 73             unbindService(mConnection);
 74         }
 75     }
 76 
 77 
 78     @Override
 79     public void onClick(View v) {
 80         switch (v.getId()) {
 81             case R.id.bt_aidl_bind:
 82 
 83                 bindService();
 84 
 85                 break;
 86             case R.id.bt_aidl_unbind:
 87                 Toast.makeText(this, "解绑成功", Toast.LENGTH_SHORT).show();
 88                 unbindService();
 89                 break;
 90             case R.id.bt_aidl_add:
 91 
 92                 if (mIsBindService && mIMyAdd != null) {
 93                     try {
 94                         int result = mIMyAdd.add(5, 5);
 95 
 96                         Toast.makeText(this, result + "", Toast.LENGTH_SHORT).show();
 97                     } catch (RemoteException e) {
 98                         e.printStackTrace();
 99                     }
100 
101                 } else {
102                     Toast.makeText(this,"没有绑定服务", Toast.LENGTH_SHORT).show();
103                 }
104 
105                 break;
106         }
107     }
108 
109 }

布局代码:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="vertical">
 6 
 7 
 8     <Button
 9         android:layout_marginTop="50dp"
10         android:id="@+id/bt_aidl_bind"
11         android:layout_width="match_parent"
12         android:layout_height="wrap_content"
13         android:text="绑定服务" />
14 
15     <Button
16         android:id="@+id/bt_aidl_unbind"
17         android:layout_width="match_parent"
18         android:layout_height="wrap_content"
19         android:text="解绑服务" />
20 
21     <Button
22         android:id="@+id/bt_aidl_add"
23         android:layout_width="match_parent"
24         android:layout_height="wrap_content"
25         android:text="AIDL测试" />
26 </LinearLayout>

上述步骤完成之后,将两个工程同时运行,即可测试客户端能否调用服务端的方法

 

二 AIDL的高级应用

上个例子是用来说明客户端通过绑定服务的方式来调用服务端的方法,下面再介绍一种客户端用来获取

服务端的对象和数据,实现服务端和客户端的数据共享;

步骤和第一个例子的步骤是一样的,首先要创建一个对象类,我们设为 Computer

创建一个computer AIDL文件来声明这个对象:

服务端代码:

1 // Computer.aidl
2 package com.jiao.myaidl.entity;
3 
4 // Declare any non-default types here with import statements
5 
6 parcelable Computer;

然后创建Computer对象类

 1 package com.jiao.myaidl.entity;
 2 
 3 import android.os.Parcel;
 4 import android.os.Parcelable;
 5 
 6 /**
 7  * Created by jiaocg on 2016/3/9.
 8  */
 9 public class Computer implements Parcelable {
10 
11 
12     public int computerId;
13     public String name;
14     public String model;
15 
16     public Computer(int computerId, String name, String model) {
17 
18         this.computerId = computerId;
19         this.name = name;
20         this.model = model;
21     }
22 
23 
24     protected Computer(Parcel in) {
25         computerId = in.readInt();
26         name = in.readString();
27         model = in.readString();
28     }
29 
30     public static final Creator<Computer> CREATOR = new Creator<Computer>() {
31         @Override
32         public Computer createFromParcel(Parcel in) {
33             return new Computer(in);
34         }
35 
36         @Override
37         public Computer[] newArray(int size) {
38             return new Computer[size];
39         }
40     };
41 
42     @Override
43     public int describeContents() {
44         return 0;
45     }
46 
47     @Override
48     public void writeToParcel(Parcel dest, int flags) {
49         dest.writeInt(computerId);
50         dest.writeString(name);
51         dest.writeString(model);
52     }
53 }

这里要特别注意创建的ComputerAIDL文件和Computer对象类 要在同一个包里:

如下图所示:

然后创建一个IComputerManager aidl文件,其中声明两个方法:

添加对象和获取所有对象

1 // IComputerManager.aidl
2 package com.jiao.myaidl;
3 
4 // Declare any non-default types here with import statements
5 import com.jiao.myaidl.entity.Computer;
6 interface IComputerManager {
7    void addComputer(in Computer computer);
8    List<Computer> getComputerList();
9 }

创建一个ComputerService

 1 package com.jiao.myaidl;
 2 
 3 import android.app.Service;
 4 import android.content.Intent;
 5 import android.os.IBinder;
 6 import android.os.RemoteException;
 7 
 8 import com.jiao.myaidl.entity.Computer;
 9 
10 import java.util.List;
11 import java.util.concurrent.CopyOnWriteArrayList;
12 
13 public class ComputerService extends Service {
14     public ComputerService() {
15     }
16 
17 
18     private CopyOnWriteArrayList<Computer> mComputerList = new CopyOnWriteArrayList<>();
19 
20     private final IComputerManager.Stub mBinder = new IComputerManager.Stub() {
21 
22 
23         @Override
24         public void addComputer(Computer computer) throws RemoteException {
25 
26 
27             mComputerList.add(computer);
28         }
29 
30         @Override
31         public List<Computer> getComputerList() throws RemoteException {
32             return mComputerList;
33         }
34     };
35 
36 
37     @Override
38     public void onCreate() {
39         super.onCreate();
40         mComputerList.add(new Computer(0, "苹果", "model1"));
41         mComputerList.add(new Computer(1, "联想", "model2"));
42         mComputerList.add(new Computer(2, "华为", "model3"));
43     }
44 
45     @Override
46     public IBinder onBind(Intent intent) {
47         // TODO: Return the communication channel to the service.
48 //        throw new UnsupportedOperationException("Not yet implemented");
49         return mBinder;
50     }
51 }

清单文件声明服务:

1  <service android:name="com.jiao.myaidl.ComputerService">
2             <intent-filter>
3                 <action android:name="com.jiao.myaidl.action.COMPUTER_SERVICE" />
4 
5                 <category android:name="android.intent.category.DEFAULT" />
6             </intent-filter>
7 
8         </service>

 

客户端代码:

首先和服务端一样要创建同样的Computer AIDL文件和Computer对象 并且包名要一致

(即客户端 Computer aidl文件的包名和Computer对象的包名要一致 同时 也要和服务器存放computer的包名一致)

创建Computer AIDL文件

 1 // Computer.aidl
 2 package com.jiao.myaidl.entity;
 3 
 4 // Declare any non-default types here with import statements
 5 
 6 
 7     /**
 8      * Demonstrates some basic types that you can use as parameters
 9      * and return values in AIDL.
10      */
11     parcelable Computer;

创建Computer对象

 1 package com.jiao.myaidl.entity;
 2 
 3 import android.os.Parcel;
 4 import android.os.Parcelable;
 5 
 6 /**
 7  * Created by jiaocg on 2016/3/10.
 8  */
 9 
10 public class Computer implements Parcelable {
11 
12 
13     public int computerId;
14     public String name;
15     public String model;
16 
17     public Computer(int computerId, String name, String model) {
18 
19         this.computerId = computerId;
20         this.name = name;
21         this.model = model;
22     }
23 
24 
25     protected Computer(Parcel in) {
26         computerId = in.readInt();
27         name = in.readString();
28         model = in.readString();
29     }
30 
31     public static final Creator<Computer> CREATOR = new Creator<Computer>() {
32         @Override
33         public Computer createFromParcel(Parcel in) {
34             return new Computer(in);
35         }
36 
37         @Override
38         public Computer[] newArray(int size) {
39             return new Computer[size];
40         }
41     };
42 
43     @Override
44     public int describeContents() {
45         return 0;
46     }
47 
48     @Override
49     public void writeToParcel(Parcel dest, int flags) {
50         dest.writeInt(computerId);
51         dest.writeString(name);
52         dest.writeString(model);
53     }
54 }

客户调用代码

  1 package com.jiao.myaidl;
  2 
  3 import android.content.ComponentName;
  4 import android.content.Context;
  5 import android.content.Intent;
  6 import android.content.ServiceConnection;
  7 import android.os.Bundle;
  8 import android.os.IBinder;
  9 import android.os.RemoteException;
 10 import android.support.v7.app.AppCompatActivity;
 11 import android.view.View;
 12 import android.widget.Button;
 13 import android.widget.Toast;
 14 
 15 import com.google.android.gms.appindexing.AppIndex;
 16 import com.google.android.gms.common.api.GoogleApiClient;
 17 import com.jiao.myaidl.client.R;
 18 import com.jiao.myaidl.entity.Computer;
 19 
 20 import java.util.List;
 21 
 22 public class Main2Activity extends AppCompatActivity implements View.OnClickListener {
 23 
 24     private boolean mIsBindService;//是否绑定了服务
 25     private IComputerManager mRemoteComputerManager;
 26     private Button bt_aidl_add;
 27     private Button bt_aidl_bind;
 28     private Button bt_aidl_unbind;
 29 
 30 
 31     //在IBinder代表的进程退出时被调用 IBinder死亡时调用
 32     //自定义的死亡通知接受者必须要重写父类DeathRecipient的成员函数binderDied。
 33     // 当Binder驱动程序通知一个Binder代理对象它所引用的Binder本地对象已经死亡时,
 34     // 就会调用它所指定的死亡通知接受者的成员函数binderDied。
 35     private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
 36 
 37         @Override
 38         public void binderDied() {
 39 
 40             if (mRemoteComputerManager != null) {
 41                 mRemoteComputerManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
 42                 mRemoteComputerManager = null;
 43                 bindService();
 44 
 45             }
 46         }
 47     };
 48 
 49 
 50     private ServiceConnection mConnection = new ServiceConnection() {
 51         @Override
 52         public void onServiceConnected(ComponentName name, IBinder service) {
 53 
 54             mIsBindService = true;
 55             Toast.makeText(Main2Activity.this, "绑定服务成功", Toast.LENGTH_SHORT).show();
 56             mRemoteComputerManager = IComputerManager.Stub.asInterface(service);
 57 
 58             try {
 59                 //注册 IBinder 死亡通知
 60                 mRemoteComputerManager.asBinder().linkToDeath(mDeathRecipient, 0);
 61             } catch (RemoteException e) {
 62                 e.printStackTrace();
 63             }
 64         }
 65 
 66         @Override
 67         public void onServiceDisconnected(ComponentName name) {
 68 
 69             mRemoteComputerManager = null;
 70         }
 71     };
 72     /**
 73      * ATTENTION: This was auto-generated to implement the App Indexing API.
 74      * See https://g.co/AppIndexing/AndroidStudio for more information.
 75      */
 76     private GoogleApiClient client;
 77 
 78 
 79     @Override
 80     protected void onCreate(Bundle savedInstanceState) {
 81         super.onCreate(savedInstanceState);
 82         setContentView(R.layout.activity_main2);
 83 
 84         initView();
 85         // ATTENTION: This was auto-generated to implement the App Indexing API.
 86         // See https://g.co/AppIndexing/AndroidStudio for more information.
 87         client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
 88     }
 89 
 90 
 91     private void initView() {
 92 
 93         bt_aidl_bind = (Button) findViewById(R.id.bt_aidl_bind);
 94         bt_aidl_unbind = (Button) findViewById(R.id.bt_aidl_unbind);
 95         bt_aidl_add = (Button) findViewById(R.id.bt_aidl_add);
 96         bt_aidl_add.setOnClickListener(this);
 97         bt_aidl_bind.setOnClickListener(this);
 98         bt_aidl_unbind.setOnClickListener(this);
 99     }
100 
101 
102     @Override
103     public void onClick(View v) {
104         switch (v.getId()) {
105             case R.id.bt_aidl_bind:
106 
107                 bindService();
108 
109                 break;
110             case R.id.bt_aidl_unbind:
111                 Toast.makeText(this, "解绑成功", Toast.LENGTH_SHORT).show();
112                 unbindService();
113                 break;
114             case R.id.bt_aidl_add:
115 
116                 if (!mIsBindService || mRemoteComputerManager == null){
117                     Toast.makeText(this,"not bind service",Toast.LENGTH_SHORT).show();
118                     return;
119                 }
120                 try {
121                     List<Computer> computerList = mRemoteComputerManager.getComputerList();
122                     for (int i =0;i<computerList.size();i++){
123                         String str = "computerId:" + String.valueOf(computerList.get(i).computerId) +
124                                 " brand:" + computerList.get(i).name +
125                                 " model:" + computerList.get(i).model ;
126 
127                         System.out.println(str);
128                     }
129                 } catch (RemoteException e) {
130                     e.printStackTrace();
131                 }
132 
133                 break;
134         }
135     }
136 
137 
138     private void bindService() {
139 
140         Intent it = new Intent();
141         it.setAction("com.jiao.myaidl.action.COMPUTER_SERVICE");
142         it.setPackage("com.jiao.myaidl.server");
143         mIsBindService = bindService(it, mConnection, Context.BIND_AUTO_CREATE);
144 
145     }
146 
147     private void unbindService() {
148 
149         if (!mIsBindService) {
150             return;
151         }
152         mIsBindService = false;
153         unbindService(mConnection);
154     }
155 
156 
157 }

以上就实现了客户端从服务器获取对象,并使用对象,实现了服务端和客户端的数据共享。

 

posted @ 2016-03-10 16:28  Android、Boy  阅读(274)  评论(0编辑  收藏  举报