当前位置:网站首页>AIDL 简介以及使用

AIDL 简介以及使用

2022-08-11 05:22:00 hqhe260

1 AIDL简介

AIDL(Android 接口定义语言),可以使用它定义客户端与服务端进程间通信(IPC)的编程接口。在

Android系统中,每个进程都运行在一块独立的内存中,在其中完成自己的各项活动,与其他进程都分 隔开来。可是有时候我们又有应用间进行互动的需求,比较传递数据或者任务委托等, AIDL就是为了满 足这种需求而诞生的。通过AIDL,可以在一个进程中获取另一个进程的数据和调用其暴露出来的方法, 从而满足进程间通信的需求。

AIDL是用于定义服务端和客户端通信接口的一种描述语言,可以拿来生产IPC代码,从某种意义上说

AIDL其实就是一个模板,因为在使用过程中,实际起作用的并不是AIDL文件,而是据此生产的一个

Interface的实例代码, AIDL其实是为了避免我们重复写代码而出现的一个模板。

2,为什么要设计这门语言?

设计这门语言的目的是为了实现进程间通信,尤其是在涉及多进程并发情况下的进程间通信

3,它有哪些语法?


其实AIDL这门语言非常的简单,基本上它的语法和 Java 是一样的,只是在一些细微处有些许差别——毕竟它只是被创造出来简化Android程序员工作的,太复杂不好——所以在这里我就着重的说一下它和 Java 不一样的地方。主要有下面这些点:

文件类型:用AIDL书写的文件的后缀是 .aidl,而不是 .java。


数据类型:AIDL默认支持一些数据类型,在使用这些数据类型的时候是不需要导包的,但是除了这些类型之外的数据类型,在使用之前必须导包,就算目标文件与当前正在编写的 .aidl 文件在同一个包下——在 Java 中,这种情况是不需要导包的。比如,现在我们编写了两个文件,一个叫做 Book.java ,另一个叫做 BookManager.aidl,它们都在 com.lypeer.aidldemo 包下 ,现在我们需要在 .aidl 文件里使用 Book 对象,那么我们就必须在 .aidl 文件里面写上 import com.lypeer.aidldemo.Book; 哪怕 .java 文件和 .aidl 文件就在一个包下。
默认支持的数据类型包括:


Java中的八种基本数据类型,包括 byte,short,int,long,float,double,boolean,char。
String 类型。
CharSequence类型。
List类型:List中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable(下文关于这个会有详解)。List可以使用泛型。
Map类型:Map中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable。Map是不支持泛型的。

4. 使用流程

1 . 在 .aidl 文件中定义 AIDL 接口,并将其添加到应用工程的 src 目录下,创建完成之后 rebuild 2. Android SDK 工具会自动生成基于该 .aidl 文件的 IBinder 接口,具体的业务对象实现这个接口, 这个具体的业务对象也是 IBinder 对象,当绑定服务的时候会根据实际情况返回具体的通信对象 (本地还是代理)

3. 将客户端绑定到该服务上,之后就可以调用 IBinder 中的方法来进行进程间通信(IPC)

4.1下面从几个方面介绍AIDL的使用

1 . 创建.aildl 文件

2. 具体的业务对象实现基于 .aidl 文件生成的接口

3. 向客户端公开接口

4. 客户端远程调用

5. 验证 AIDL

4.1.1 创建.aildl 文件

在 AIDL 中可以通过可带参数以及返回值的一个或多个方法来声明接口,参数和返回值可以是任意类 型, AIDL 中支持的数据类型如下:

java 的 8 种数据类型: byte、 short、 int、 long、 float、 double、 boolean、 char

除此之外支持 String、 charSequence、 List、 Map

自定义数据类型 如果参数或返回值类型为 List 或 Map 时:

List 中的所有元素都必须是 AIDL 支持的数据类型、其他 AIDL 生成的接口或自己声明的可打包类 型。可选择将 List 用作“通用”类(例如, List)。另一端实际接收的具体类始终是 ArrayList,但生 成的方法使用的是 List 接口。

Map 中的所有元素都必须是 AIDL 支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类 型。 不支持通用 Map(如 Map 形式的 Map)。 另一端实际接收的具体类始终 是 HashMap,但生成的方法使用的是 Map 接口。

4.1.2 具体的业务对象实现基于 .aidl 文件生成的接口

1.首先,在工程的 src 目录下创建 .aidl 文件,具体如下图所示:

 

2.打开IPersonAidlInterface.aidl,在 .aidl 文件中添加具体的业务方法,文件内容如下:

package com . manu . aidl demo ;

// Declare any non-default types here with import statements

interface IPersonAi dlInterface {
    //具体的业务

    void setName (String name) ;
    void setAge (int age) ;
    String getInfo () ;
    /**

     * Demonst rates some basic types that you can use as paramete rs

     * and return values in AIDL .

     */

    void basicTypes (int anInt , long aLong , boolean aBoolean , float aFloat , 

double aDouble , String aString) ;
}

3.然后,重新 rebuild project , Android SDK 工具会在相应的目录生成对应的与 .aidl 文件同名的 .java

接口文件,具体目录如下:

 

4. 那么这个业务要体现在什么地方呢,从上面可知 Stub 是一个抽象类,那么它所提供的具体业务必 然需要一个具体的实现类来完成,下面实现这个具体的业务类,具体如下:

public class IPersonImpl extends IPersonAi dlInterface . Stub {
    private String name ;
    private int age ;
    @Override

    public void setName (String name) throws RemoteExcepti on {
        this . name = name ;
   }
    @Override

    public void setAge (int age) throws RemoteExcepti on {
        this . age = age ;
   }
    @Override

    public String getInfo () throws RemoteExcepti on {
        return "My name is "+name+" , age is "+age+" ! " ;
   }
    @Override

    public void basi cTypes (int anInt , long aLong , boolean aBoolean , float 

aFloat , double aDouble , String aString) throws RemoteExcepti on {
   }
}

3.3.3 向客户端公开接口

创建一个 Service 以便对外提供具体的业务,具体如下:

// Service

public class PersonSe rvice extends Service {
    publicPe rsonService () {
   }
    @Override

    public IBinder onBind (Intent intent) {
        return new IPersonImpl () ;
   }
}

当外部调用 bindService() 方法绑定服务时,就会调用 onBind() 方法返回 IBinder 对象,这个 IBinder

对象也是具体的业务对象,如这里的 onBind() 方法返回的也是具体的业务对象,两者是统一的。此外, 创建的 Service 要在 AndroidManifest.xml 文件中声明,具体如下:

service

    android : name=" . PersonService"

    android : enabled="true"

    android : exported="true"

    android : process=" : remote">
</service>

其中使用 process 关键字表示为该服务开启一个独立的进程, remote 可任意,表示进程名称, ":"将会 在主进程(进程名为包名)添加新名称作为新进程的名称,如 com.hopu.study 将会变成

com.hopu.study:remote。

4.1.3 客户端远程调用

通过上面几步完成了服务的搭建,并将服务运行在独立进程中,下面主要就是客户端的具体调用了,具 体实现参考如下:

public class MainActivity extends AppCompatActi vity {
    
    private Button btn_start_service , btn_stop_service , btn_call _remote ;
    private static final String TAG = "MainActivity" ;
    private IPrsonAidl Interface iPersonAi dlInterface ;
    @Override

    protected void onCreate (Bundl e savedInstanceState) {
        super . onCreate (savedInstanceState) ;
        setContentView(R . layout . activity_main) ;
        btn_start_service = findViewById (R . i d . btn_start_service) ;
        btn_stop_se rvi ce = fi ndVi ewById (R.id.btn_stop_service) ;
        btn_cal l _remote = findViewById (R . id . btn_call _remote) ;
        btn_start_servi ce . setOnClickListener (new View . OnClickListene r () {
            @Override

            public void onClick(Vi ew v) {
                bindService Click(v) ;
           }       }) ;
        btn_stop_servi e . setOnClickListener (new Vi ew . OnCl i ckLi stene r () {
            @Override

            public void onClick(View v) {
                unbindSe rviceClick(v) ;
           }
       }) ;
        btn_call _remote . setOnClick Listener (new View . OnClick Listener () {
            @Overr de

            public void onClick(View v) {
                call RemoteClick(v) ;
           }
       }) ;
   }
    public void bindService Cick(View view) {
        Log . i (TAG , "绑定服务 . . . ") ;
        Intent intent = new Intent (this , PersonSe rvice . class) ;
        // 绑定服务时自动创建服务

        bindService (intent , conn , Context . BIND_AUTO_CREATE) ;
   }
    public void unbindSe rviceCl i ck(View view) {
        Log . i (TAG , "解绑服务 . . . ") ;
        unbindService (conn) ;
   }
    public void call RemoteClick(View view) {
        Log . i (TAG , "远程调用具体服务 . . . ") ;
        try {
            iPersonAidl Interface . setName ("Tom") ;
            iPersonAidl Interface . setAge (10) ;
            String info = iPersonAidl Interface . getInfo () ;
            System . out . println ("这是远程调用的服务信息: "+info) ;
       } catch (RemoteExcepti on e) {
            e . printStackTrace () ;
       }
   }
    private Servi ceConnection conn = new Service Connection () {
        @Override

        public void onService Connected (ComponentName name , IBinde rservice) {
            // 根据实际情况返回 IBinder 的本地对象或其代理对象

            iPersonAidl Interface = 

IPersonAidl Interface . Stub . asInterface (service) ;
            System . out . println ("具体的业务对象: "+iPersonAi dlInterface) ;
       }
        @Override

        public void onService Disconnected (ComponentName name) {
            // Service 意外中断时调用
}};

4.1.4 验证 AIDL

通过前面几步,服务端与客户端已经完成,下面来验证能否调用具体的业务,这里分两种情况:

1、相同进程 创建 Service 的时候不要在 AndroidManifest.xml 文件中不要使用 process 开启独立进程即可,此时服 务进程默认与客户端属于统一进程,结果如下:

 

2、不同进程 显然,如果服务与客户端处于不同进程,也就是常常说的进程间通信,具体是由 IBinder 对象的代理对 象完成,反之,使用本地对象,也就是本地的 IBinder 对象,具体就是实现 AIDL 的业务类所生成的对象

 

原网站

版权声明
本文为[hqhe260]所创,转载请带上原文链接,感谢
https://blog.csdn.net/heqiang260/article/details/126093599