在Android中每个应用程序都运行在自己的进程空间,不同的进程不能直接访问对方的进程空间,如果要在进程间通信,必须将传递对象解析成操作系统可以理解的基本类型,通过操作系统作为桥梁来传递到对方的进程。
AIDL(Android Interface Definition Language) Android 接口定义语言用于生成两个进程之间进行进程间通信的代码。

AIDL服务端实现

定义AIDL接口
  • AIDL接口文件的后缀名为.aidl.保存在src目录下
  • AIDL接口文件与一般的接口大体相似,都是以interface作为关键字,每个aidl文件只能定义一个接口,与一般接口不同的是AIDL文件只能定义接口声明和方法声明,不能定义静态常量。
  • AIDL文件中方法声明的参数和返回值可以是基本数据类型,String,CharSequence,List,Map,实现了Parcelable接口的类,甚至是其他AIDL生成的接口。其中后两者即使位于同一个包也需要使用import包含进来。实现了Parcelable接口的类除了要建立一个实现android.os.Parcelable接口的类外,还需要为这个类单独建立一个aidl文件,并使用parcelable关键字进行声明。
  • 除了基本类型,String,CharSequence这些类型,其他的都需要指明方向,in表示由客户端设置,out表示由服务端设置,inout表示两者均可设置。
  • 如果其他应用程序需要进行IPC,则这些应用程序的src也需要有这个aidl文件
  1. 首先,先创建一个继承Service的服务类 MyAIDLService

  1. 紧接着选中刚刚创建的MyAIDLService.java文件在右键弹出的菜单中选择File->New->AIDL->AIDL File
    这时候就会在main目录下自动创建一个aidl目录,并且在MyAIDLService.java 平行的对应包下创建一个aidl文件。
package com.idealist.testaidl.service;

import com.idealist.testaidl.bean.Person;
import com.idealist.testaidl.callback.IResultCallback;
interface IMyAidlInterface {
void savePersonInfo(in Person person,IResultCallback callback);//保存用户信息
List<Person> getPersonInfos();//获取所有用户信息的列表
}

这里用到了Person这个Bean以及IResultCallback这个回调接口,前者是实现了Parcelable接口的类,后者是其他AIDL生成的接口。具体如下:
com/idealist/testaidl/callback/IResultCallback.aidl

package com.idealist.testaidl.callback;

interface IResultCallback {
void reportResult(String result);
}

com/idealist/testaidl/bean/Person.aidl

package com.idealist.testaidl.bean;
parcelable Person;

下面是Person的实现类:
com.idealist.testaidl.bean.Person

package com.idealist.testaidl.bean;
import android.os.Parcel;
import android.os.Parcelable;

public class Person implements Parcelable {

public Person() {}
protected Person(Parcel in) {
name = in.readString();
tel = in.readString();
}

public static final Creator<Person> CREATOR = new Creator<Person>() {
@Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}

@Override
public Person[] newArray(int size) {
return new Person[size];
}
};

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getTel() {
return tel;
}

public void setTel(String tel) {
this.tel = tel;
}

private String name = null;
private String tel = null;


@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(name);
parcel.writeString(tel);
}
}

点击build后就可以编译,编译结束后就可以产生如下的Stub文件了:

  1. 实现MyAIDLService类:
    这里实现的功能很简单就是在客户端绑定并调用Serive的savePersonInfo方法的时候,将会存储起来,如果客户端调用getPersonInfos将会返回存储信息的列表。
package com.idealist.testaidl.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;

import com.idealist.testaidl.bean.Person;
import com.idealist.testaidl.callback.IResultCallback;

import java.util.ArrayList;
import java.util.List;

public class MyAIDLService extends Service {
private List<Person> mPersonInfoList = new ArrayList<Person>();

private IMyAidlInterface.Stub mIBinder = new IMyAidlInterface.Stub() {
@Override
public void savePersonInfo(Person person, IResultCallback callback) throws RemoteException {
if(mPersonInfoList != null && person != null) {
mPersonInfoList.add(person);
Log.i("xiaohai.lin", "Name = " + person.getName() + " -- " +
"Tel " + person.getTel() + " Has add to list");
}
if(callback != null) {
callback.reportResult("Person info had add Sucessfully !");
}
}

@Override
public List<Person> getPersonInfos() throws RemoteException {
return mPersonInfoList;
}
};

@Nullable
@Override
public IBinder onBind(Intent intent) {
return mIBinder;
}

public boolean onUnbind(Intent intent) {
Log.i("xiaohai.lin", "客户端解除绑定");
return super.onUnbind(intent);
}
}
  1. 最后一定要注意在AndroidManifest.xml文件中作如下声明:
<service
android:name=".service.MyAIDLService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MyAIDLService" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>

整个服务端源码结构如下:

AIDL客户端实现

创建一个新的Android项目工程,将服务器端的AIDL相关的文件连同包复制到客户端项目,项目结构如下图所示:

package com.ideallist.testaidlclient;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.idealist.testaidl.bean.Person;
import com.idealist.testaidl.callback.IResultCallback;
import com.idealist.testaidl.service.IMyAidlInterface;

import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private IMyAidlInterface mInterface = null;
private Button mBindServiceBtn = null;
private Button mUnbindServceBtn = null;
private Button mSetPersonInfoBtn = null;
private Button mGetPersonInfoBtn = null;
private boolean isBind = false;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mInterface = IMyAidlInterface.Stub.asInterface(iBinder);
isBind = true;
Toast.makeText(MainActivity.this, "Binded to Server !",Toast.LENGTH_LONG).show();
}

@Override
public void onServiceDisconnected(ComponentName componentName) {
if(mInterface != null) {
mInterface = null;
}
Toast.makeText(MainActivity.this, "Ubind to Server !",Toast.LENGTH_LONG).show();
isBind = false;
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBindServiceBtn = (Button) findViewById(R.id.bindservice);
mUnbindServceBtn = (Button) findViewById(R.id.unbindservice);
mSetPersonInfoBtn = (Button) findViewById(R.id.setpersonInfo);
mGetPersonInfoBtn = (Button) findViewById(R.id.getpersonInfo);

mBindServiceBtn.setOnClickListener(this);
mUnbindServceBtn.setOnClickListener(this);
mSetPersonInfoBtn.setOnClickListener(this);
mGetPersonInfoBtn.setOnClickListener(this);
}

private IResultCallback.Stub mResultCallBack = new IResultCallback.Stub() {
@Override
public void reportResult(String result) throws RemoteException {
Toast.makeText(MainActivity.this, "Result = " + result,Toast.LENGTH_LONG).show();
}
};

@Override
public void onClick(View view) {
int id = view.getId();
switch (id) {
case R.id.bindservice:
if(!isBind) {
Intent intent = new Intent("android.intent.action.MyAIDLService");
intent.setPackage("com.idealist.testaidl");
bindService(intent, conn, BIND_AUTO_CREATE);
}
break;
case R.id.unbindservice:
if(isBind) {
unbindService(conn);
}
break;
case R.id.setpersonInfo:
if(mInterface != null ) {
Person person = new Person();
person.setName("Jimmy");
person.setTel("1111111111");
try {
mInterface.savePersonInfo(person,mResultCallBack);
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;
case R.id.getpersonInfo:
if(mInterface != null ) {
try {
List<Person> mList = mInterface.getPersonInfos();
for (Person p : mList) {
Toast.makeText(MainActivity.this,"Name = " + p.getName()+" : "+ " Tel "+ p.getTel(),Toast.LENGTH_LONG).show();
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;

}
}
}

写客户端最需要注意的就是每个类和Service中的对应关系。一旦对应错误就有可能访问不到对应的方法。

Contents
  1. 1. AIDL服务端实现
    1. 1.1. 定义AIDL接口
  2. 2. AIDL客户端实现