一、概述
AIDL是Android Interface Definition Language,即Android接口定义语言。设计这门语言的目的主要是为了是:进程间通信。在Android中,每一个进程都是单独的一个Dalvik VM实例,拥有自己独立的内存,存储数据,执行操作。AIDL就是负责定义一些两个进程间相互认可的通信规则,用来传输数据,沟通交流。
二、语法
- 文件类型:用AIDL书写的文件后缀是.aidl,而不是.java。
- 导包:使用AIDL只是的数据类型不需要导包,使用自己定义的实体类型,即使引用的实体与使用的类在同一个包下面,也要导报。列入demo中Course.java与CourseManager.aidl同在com.gyg.aidlclient下面,在CourseManager.aidl中使用Course.java也要import com.gyg.aidlclient.Course;(这个好像要手动导入,负责编译的时候会报错)。
- 数据类型:默认支持的数据类型:
*Java中的八种基本数据类型:byte,short,int,long,float,double,boolean,char。
*String类型
*CharSequence
*List list中的所有元素必须AIDL支持的类型之一,或一个其它AIDL生成的接口,或定义的parcelable。支持泛型。
*Map map中的所有元素必须是AIDL支持的类型之一,或一个其它AIDL生成的接口,或定义的parcelable。不支持泛型。 - 定向tag
*in 数据流向从客户端到服务端,服务端接收到客户端的一个完整对象,客户端接收到服务端一个空的对象。
*out 数据流向从服务端到客户端,服务端接收到客户端的一个空对象,客户端接收到服务端一个完整对象。
*inout 数据流向双向,服务端接收到客户端的一个完整对象,客户端接收到服务端的一个完整对象。 - 两种.aidl
* 定义parcelable对象,供其它aidl文件使用非默认的数据类型。例如demo中的Course.aidl。
* 定义方法接口,用来完成跨进程数据通信的。例如demo中的CourseManager.aidl。
三、示例代码
1、自定义实体类Course.java,继承自parcelable接口
public class Course implements Parcelable {
private String name;//课程名称
private double credit;//课程学分
private String teacher;//课程教师
public Course() {
}
public Course(String name, double credit, String teacher) {
this.name = name;
this.credit = credit;
this.teacher = teacher;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getCredit() {
return credit;
}
public void setCredit(double credit) {
this.credit = credit;
}
public String getTeacher() {
return teacher;
}
public void setTeacher(String teacher) {
this.teacher = teacher;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.name);
dest.writeDouble(this.credit);
dest.writeString(this.teacher);
}
public void readFromParcel(Parcel dest) {
name = dest.readString();
credit=dest.readDouble();
teacher=dest.readString();
}
protected Course(Parcel in) {
this.name = in.readString();
this.credit = in.readDouble();
this.teacher = in.readString();
}
public static final Parcelable.Creator<Course> CREATOR = new Parcelable.Creator<Course>() {
@Override
public Course createFromParcel(Parcel source) {
return new Course(source);
}
@Override
public Course[] newArray(int size) {
return new Course[size];
}
};
@Override
public String toString() {
return "Course{" +
"name='" + name + '\'' +
", credit=" + credit +
", teacher='" + teacher + '\'' +
'}';
}
}
2、定义Course.aidl,供其它aidl文件使用Course对象。
/**注意:Course.java和Course.aidl的包名应该是一样的。这里有两种方法:1.将Course.java放到与Course.aidl同一个包下,然后在module的build.gradle里面添加
sourceSets {
main {
java.srcDirs = ['src/main/java', 'src/main/aidl']
}
}
2.将Course.java放在java目录下与Course.aidl的同一目录名下。build.gradle不需要任何设置。*/
package com.gyg.aidlclient;
parcelable Course;
3.定义CourseManager.aidl,定义接口间通信的规则
// CourseManager.aidl
package com.gyg.aidlclient;
import com.gyg.aidlclient.Course;
// Declare any non-default types here with import statements
interface CourseManager {
Course getCourse();//从服务器获取一个Course对象
Course updateCourseIn(in Course course);//in方式传一个Course对象到服务器端,并接受服务器端返回的Course对象
Course updateCourseOut(out Course course);//out方式传一个Course对象到服务器端,并接受服务器端返回的Course对象
Course updateCourseInOut(inout Course course);//inout方式传一个Course对象到服务器端,并接受服务器端返回的Course对象
}
3、将aidl目录的文件原封不懂的复制到服务器端下面,(服务器端aidl文件的包名要一致,否则会编译错误);
4、服务端编写AIDLService.java
package com.gyg.aidlserver;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import com.gyg.aidlclient.Course;
import com.gyg.aidlclient.CourseManager;
/**
* Created by gyg on 2017/2/14.
*/
public class AIDLService extends Service{
private final CourseManager.Stub mCourseManager=new CourseManager.Stub(){
@Override
public Course getCourse() throws RemoteException {
return new Course("Android高级开发",17.3,"Jack");//创建并返回一个Course对象给客户端,在客户端查看是否接受到该对象,接收到则表明两个进程间成功通信
}
/**
* in方式接受一个Course对象,并
* @param course
* @return
* @throws RemoteException
*/
@Override
public Course updateCourseIn(Course course) throws RemoteException {
if (course==null){
course=new Course();
}
System.out.println("服务端In:"+course);
course.setCredit(233.3);
return course;
}
@Override
public Course updateCourseOut(Course course) throws RemoteException {
if (course==null){
course=new Course();
}
System.out.println("服务端Out:"+course);
course.setCredit(233.3);
return course;
}
@Override
public Course updateCourseInOut(Course course) throws RemoteException {
if (course==null){
course=new Course();
}
System.out.println("服务端InOut:"+course);
course.setCredit(177.77);
return course;
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mCourseManager;//返回mCourseManager给客户端,客户端利用mCourseManager与服务端进行通信
}
}
5、AndroidManifest.xml中注册AIDLService.java
<!--注意android:exported="true"一定要添加,否则客户端链接不到Service-->
<service android:name=".AIDLService"
android:exported="true"
>
<intent-filter>
<action android:name="com.gyg.aidl"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
6、客户端编写测试代码:
package com.gyg.aidlclient;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private CourseManager mCourseManager;
Course originCourse;//服务器端返回的Course对象
private boolean mBound=false;//记录service是否连接
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.updateIn).setOnClickListener(this);
findViewById(R.id.updateOut).setOnClickListener(this);
findViewById(R.id.updateInOut).setOnClickListener(this);
}
@Override
protected void onStart() {
super.onStart();
if (!mBound){
connectService();//绑定service
}
}
@Override
protected void onStop() {
super.onStop();
if (mBound=true){
unbindService(mServiceConnection);//解绑service
}
}
private ServiceConnection mServiceConnection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mCourseManager=CourseManager.Stub.asInterface(iBinder);
Log.d(getLocalClassName(),"Service Connected");
if (mCourseManager!=null){
try {
originCourse=mCourseManager.getCourse();//获取服务器返回的Course对象
((TextView)findViewById(R.id.originTxt)).setText(originCourse.toString());//显示服务器返回的对象数据
} catch (RemoteException e) {
e.printStackTrace();
}
}
mBound=true;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.d(getLocalClassName(),"Service UnConnected");
mBound=false;
}
};
//隐式链接AIDLService
private void connectService(){
Intent intent=new Intent();
intent.setAction("com.gyg.aidl");
intent.setPackage("com.gyg.aidlserver");
bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.updateIn://测试in方式返回的数据
if (mCourseManager!=null){
try {
mCourseManager.updateCourseIn(originCourse);
((TextView)findViewById(R.id.inTxt)).setText("定向IN:"+originCourse.toString());//显示定向in后originCourse数据
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;
case R.id.updateOut://测试out方式返回的数据
if (mCourseManager!=null){
try {
mCourseManager.updateCourseOut(originCourse);
((TextView)findViewById(R.id.outTxt)).setText("定向OUT:"+originCourse.toString());//显示定向out后originCourse数据
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;
case R.id.updateInOut:
if (mCourseManager!=null){//测试inout方式返回的数据
try {
mCourseManager.updateCourseInOut(originCourse);
((TextView)findViewById(R.id.inoutTxt)).setText("定向INOUT:"+originCourse.toString());//显示定向inout后originCourse数据
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;
}
}
}
四、测试结果分析
1.首先运行AIDLServer,再运行AIDLClient,成功后运行结果如下:
说明AIDLClient与AIDLServer通信成功,成功获得到AIDLServer传过来的数据
2.点击UPDATEIN按钮,服务器端输出结果:
服务器接收到客户端的一个完整对象
客户端输出结果:
服务器端的数据对客户端的数据没有影响
3.点击UPDATEOUT,服务器端结果:
服务器端接收到客户端的一个空对象
客户端结果:
客户端因为服务器端的数据的改变而更改了。
4.点击UPDATEINOUT按钮:
服务器端结果:
客户端接收到服务端的完整对象
客户端结果:
客户端因为服务端数据的变化而发生了更改。
五、demo