AndroidIPC-AIDL

AndroidIPC-AIDL

一、概述

AIDL意思即Android Interface Definition Language,翻译过来就是android接口定义语言,是用于定义服务器和客户端通信接口的一种描述语言,可以拿来生成用于IPC的代码。从某种意义上说AIDL其实是一个模板,因为在使用过程中,实际起作用的并不是AIDL文件,而是据此生成的一个Interface的实例代码,AIDL其实是为了避免我们重复编写代码而出现的一个模板。

通过AIDL,可以在一个进程中获取另一个进程的数据和调用其暴露出来的方法,从而满足进程间通信的需求。通常,暴露方法给其他应用进行调用的应用称为服务端,调用其他应用的方法的应用称为客户端,客户端通过绑定服务端的Service来进行交互。

二、语法

AIDL的语法十分简单,与Java语言基本保持一致,需要记住的规则有以下几点:

1.AIDL文件以.aidl为后缀名

2.AIDL支持的数据类型分为以下几种

  • 八种基本数据类型
  • String,CharSequence
  • 实现了Parcelable接口的数据类型
  • List类型,List承载的数据必须是AIDL支持的类型,或者是其他生命的AIDL对象
  • Map类型,Map承载的数据必须是AIDL支持的类型,或者是其他生命的AIDL对象

3.AIDL文件可以分为两类。一类用来声明实现了Parcelable接口的数据类型,以供其他AIDL文件使用那些非默认支持的数据类型。还有一类用来定义接口方法,声明要暴露哪写接口给客户端调用,定向Tag用来标注这些方法的参数

4.定向Tag。定向Tag表示在跨进程通信中数据的流向,用于标注方法的参数值,分别为in,out,inout三种。其中in表示数据只能从客户端流向服务端,out表示数据只能由服务端流向客户端,而inout则表示数据可以在服务端口和客户端之间双向流通。此外,如果AIDL方法接口的参数值类型是基本数据类型,那么这些参数的定向Tag默认且只能是in

5.明确导包。在AIDL文件中需要明确标明引用到的数据类型所在的包名,即使两个文件处在同一个包下。

三、服务端编码

新建一个工程,包名为com.example.aidlserver

首先,在应用中需要用到一个Student类,而Student类是两个应用间都需要用到的,所以也需要在AIDL中声明Student类,为了避免出现类名重复导致无法创建文件的错误,这里需要先建立StudentAidl文件,之后再创建Student类

右键点击新建一个AIDL文件,命名为Student。创建完成之后,系统会默认创建一个aidl文件夹

可以删掉文件中自动生成的接口和方法,因为这个aidl文件主要是为了声明Student类

在这里插入图片描述

接下来定义Student类,并且实现Parcelable接口

public class Student implements Parcelable {
    private String name;
    private int age;
    private boolean isAdult;

    public Student(){}
    public Student(String name, int age, boolean isAdult) {
        this.name = name;
        this.age = age;
        this.isAdult = isAdult;
    }

    protected Student(Parcel in) {
        name = in.readString();
        age = in.readInt();
        isAdult = in.readByte() != 0;
    }

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

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public boolean isAdult() {
        return isAdult;
    }

    public void setAdult(boolean adult) {
        isAdult = adult;
    }

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(age);
        dest.writeByte((byte) (isAdult ? 1 : 0));
    }

    public void readFromParcel(Parcel parcel){
        name = parcel.readString();
        age = parcel.readInt();
        isAdult = parcel.readByte()==1;
    }
}

然后,定义接口aidl文件,我们提供四个方法

interface IMyAidlInterface {
    String getName();

    void sendStudent(inout Student student);

    void sendStudentIn(in Student student);

    void sendStudentOut(out Student student);
}

第一个方法用于向客户端返回数据

第二,三,四个方法用于客户端向服务端提交数据,分别验证三个定向Tag的区别

之前说过,在进程间通信中真正起作用的并不是AIDL文件,而是系统据此而生成的文件,可以在以下目录查看系统生成的文件。
在这里插入图片描述

创建或者修改AIDL文件后,需要Make Project,这样系统才能生成我们需要的文件

接下来需要创建一个Service供客户端远程绑定了

public class MyService extends Service {

    private IMyAidlInterface iMyAidlInterface = new IMyAidlInterface.Stub() {
        @Override
        public String getName() throws RemoteException {
            return "test";
        }

        @Override
        public void sendStudent(Student student) throws RemoteException {
            Log.d("InOut", "name = " +student.getName());
            Log.d("InOut", "age = "+student.getAge());
            Log.d("InOut", "isAdult = " +student.isAdult());
            student.setName("服务端修改了student的name InOut");
        }

        @Override
        public void sendStudentIn(Student student) throws RemoteException {
            Log.d("In", "name = " +student.getName());
            Log.d("In", "age = "+student.getAge());
            Log.d("In", "isAdult = " +student.isAdult());
            student.setName("服务端修改了student的name In");
        }

        @Override
        public void sendStudentOut(Student student) throws RemoteException {
            Log.d("Out", "name = " +student.getName());
            Log.d("Out", "age = "+student.getAge());
            Log.d("Out", "isAdult = " +student.isAdult());
            student.setName("服务端修改了student的name Out");
        }
    };
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return iMyAidlInterface.asBinder();
    }
}

可以看到,我们声明了一个IMyAidlInterface的实例,并重写了它的四个方法。

在onBind方法中我们返回的是iMyAidlInterface.asBinder();

最后,服务端还有一个地方需要注意

因为服务端的Service需要被客户端远程绑定,所以客户端要能找到这个Service,可以通过先指定包名,之后再配置action的值来找到Service,需要在manifest文件中修改Service的注册。

		<service>
            android:name=".MyService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="serverService"/>
            </intent-filter>
        </service>

四、客户端编码

客户端需要再新建一个工程,包名为com.example.aidlclient

将服务端中的AIDL文件以及Student类复制过来,将aidl文件夹整个复制到和java文件夹同一层级下,不需要改动任何代码

AIDLServer

在这里插入图片描述

AIDLClient

在这里插入图片描述

修改布局文件,添加三个按钮

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="InOut"
        android:id="@+id/inout"
        android:onClick="onClick"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="In"
        android:id="@+id/in"
        android:onClick="onClick"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Out"
        android:id="@+id/out"
        android:onClick="onClick"/>
</LinearLayout>
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    private IMyAidlInterface iMyAidlInterface;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent();
        intent.setAction("serverService");
        intent.setPackage("com.example.aidlserver");
        bindService(intent,connection,BIND_AUTO_CREATE);

    }

    public void onClick(View view) {
        switch(view.getId()){
            case R.id.inout:
                Student student = new Student("inout student",20,true);
                try {
                    iMyAidlInterface.sendStudent(student);
                    Log.d(TAG, "新名字 = "+student.getName());
                    Toast.makeText(this, iMyAidlInterface.getName(), Toast.LENGTH_SHORT).show();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
            case R.id.out:
                Student studentOut = new Student("out student",20,true);
                try {
                    iMyAidlInterface.sendStudentOut(studentOut);
                    Log.d(TAG, "新名字 = "+studentOut.getName());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
            case R.id.in:
                Student studentIn = new Student("in student",20,true);
                try {
                    iMyAidlInterface.sendStudentIn(studentIn);
                    Log.d(TAG, "新名字 = "+studentIn.getName());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
        }


    }
}

先绑定ServiceiMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);,通过这行代码获取到接口的实例,通过这个调用那四个方法。

我们按顺序分别点击了InOut,In,Out

结果

InOut

AIDLClient
在这里插入图片描述

AIDLServer
在这里插入图片描述

可以看到,student的信息可以传到服务端中,而且服务端中对name的修改也会同步到客户端

In

AIDLClient
在这里插入图片描述

AIDLServer
在这里插入图片描述

可以看到,数据可以从客户端传到服务端,但是服务端对name的修改并没有同步到客户端

也就是说数据只能从客户端传到服务端

Out

AIDLClient
在这里插入图片描述

AIDLServer
在这里插入图片描述

可以看到,客户端的数据并没有传入到服务端中,而服务端中对name的修改却同步到了客户端

也就是说数据只能从服务端传到客户端。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值