使用Android接口描述语言(AIDL)
24 Sep 2013AIDL简介
Andorid提供了一种轻量级的进程间通信机制:接口描述语言(Android Interface Definition Language),简称AIDL。进程间使用AIDL通信跟使用Intent通信的最大区别在于:前者是同步通信,而后者是异步通信。AIDL的语法与JAVA中的Interface十分相似,对数据类型的支持方面有一些差别,目前AIDL支持的数据类型有:
- Java中的基本数据类型
- String
- List
- CharSequence
- Map
- 其他AIDL生成的接口
- 实现了Parcelable接口并通过值传递的自定义类型
使用AIDL的步骤
- 创建.aidl文件,在文件中声明远程服务的接口
- 在.java文件中实现.aidl中声明的方法
- 在AndroidMainifest中注册上面创建的服务
- 客户端请求绑定服务成功后就可以调用.aidl中声明的方法了
示例解析
项目目录结构:
-
在项目src文件夹下创建IAddService.aidl文件,在aidl声明了一个addOne方法,这个方法简单的把传入的值加上一。
IAddService.aidl:
package net.lnmcc.aidltest.aidl; interface IAddOneService { int addOne(int value); }
保存.aidl文件后,Eclipse将会自动在gen/文件夹下生成一个IAddService.java文件,在后面实现远程服务的时候会使用到其中的抽象类Stub。
-
创建AddService,AddService是一个bound服务,需要实现onBind()方法,它将返回一个IAddService.Stub实例。IBinder简单的理解成进程间通信的通道,可以通过这个通道来实现数据传输。
AddService.java:
public class AddService extends Service { IAddService.Stub mBinder; @Override public void onCreate() { super.onCreate(); mBinder = new IAddService.Stub() { //简单的把参数加 1 @Override public addOne(int value) throws RemoteException { return value + 1; } }; } //当客户端请求绑定服务成功后,会调用这个方法,并把mBinder返回, //mBinder引用了一个IAddService.Stub实例,从而使得客户端可以 //成功调用IAddService.Stub中的方法,于是mBinder成了一个通信通道 @Override public IBinder onBind(Intent arg0) { return mBinder; } @Override public void onDestroy() { super.onDestroy(); } }
接下来需要在AndroidManifest.xml中声明service:
<service android:name="net.lnmcc.aidltest.AddService" android:process="net.lnmcc.aidltest.AddService" />
需要说明的是android:process指示把这个service当做一个独立的进程来执行,进程名字即”net.lnmcc.aidltest.AddService”。之所以这么做是因为我们是在一个app中演示进程间通信。当运行本例子的时候,使用ps grep aidl命令可以看到有2个进程。但在一般情况下,service和client分属于2个app,自然属于两个不同进程,并不需要声明android:process 。 -
创建client端,连接IAddService,连接成功后就可以像调用本地方法一样调用远程方法(这里称AIDL中声明的方法为远程方法)。
public class AddClient extends Activity { IAddService service; //myServiceConnection用来管理服务连接, //服务连接成功后会调用onServiceConnected方法, //断开连接时会调用onServiceDisconnected方法 myServiceConnection connection; class myServiceConnection implements ServiceConnection { //服务连接成功时调用, //IAddService.Stub.asInterface()是一个辅助方法, //可以把IBinder类型的变量转换成IAddService类型 @Override public void onServiceConnected(ComponentName name, IBinder boundservice) { service = IAddService.Stub.asInterface(boundservice); Toast.makeText(AddClient.this, "Service connected", Toast.LENGTH_SHORT).show(); } @Override public void onServiceDisconnected(ComponentName name) { service = null; Toast.makeText(AddClient.this, "Service disconnected", Toast.LENGTH_SHORT).show(); } } private void initService() { connection = new myServiceConnection(); //创建一个action intent, 用来连接到远程服务。 //服务名字必须跟前面在AndroidManifest.xml中注册的一样 Intent i = new Intent(); i.setClassName("net.lnmcc.aidltest", net.lnmcc.aidltest.AddService.class.getName()); //请求绑定到Intent指定的远程服务 //第二个参数是用来具体处理连接的ServiceConnection对象 //BIND_AUTO_CREATE标志表示如果服务不存在,则自动启动 if(!bindService(i, connection, Context.BIND_AUTO_CREATE)) { Toast.makeText(AddClient.this, "Bind Service Failed", Toast.LENGTH_SHORT).show(); } } private void releaseService() { unbindService(connection); connection = null; } private TextView result; private EditText value; private Button btnAdd; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //这是app的主activity,布局中包括了一个用于输入值的EditText //一个显示结果的TextView和一个提交按钮 setContentView(R.layout.activity_main); result = (TextView)findViewById(R.id.result); value = (EditText)findViewById(R.id.value); initService(); btnAdd = (Button)findViewById(R.id.addone); btnAdd.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int v1, res = 0; try{ v1 = Integer.parseInt(value.getText().toString()); res = service.addOne(v1); }catch(RemoteException e) { e.printStackTrace(); } result.setText(Integer.valueOf(res).toString()); } }); } @Override protected void onDestroy() { releaseService(); super.onDestroy(); } }
-
AndroidManifest.xml:
<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="net.lnmcc.aidltest.AddClient" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name="net.lnmcc.aidltest.AddService" android:process="net.lnmcc.aidltest.AddService" /> </application>
5.activity_main.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:text="Android AIDL" android:textSize="22dp" > <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/value" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <Button android:id="@+id/addone" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="+1" /> </LinearLayout> <TextView android:id="@+id/result" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="result" /> </LinearLayout>
-
git clone https://github.com/lnmcc/AIDLTest.git