小工具知识网

当前位置: 首页 > 行业知识 > Android:AIDL简单介绍+传递简单数据+传递复杂数据

行业知识

Android:AIDL简单介绍+传递简单数据+传递复杂数据

2026-11-03 00:51:31 来源:互联网转载

对于AIDL的学习,这些也只能说是我在学习中的理解,有理解不到位或者错的地方也欢迎指正。


1.AIDL的简单介绍

AIDL的目的就是实现进程之间的通信,尤其是在涉及多进程并发情况下的进程间通信。可以将aidl理解为两个进程之间的桥梁,并制定规则,使其传输特定数据。

1.AIDL支持的数据类型有:
  1. 基本数据类型(int、long、char、boolean、double),定向 tag 默认且只能是 in
  2. string和charSequence,定向 tag 默认且只能是 in
  3. list:只支持arraylist,以及里面的所有元素必须被aidl支持
  4. map:只支持hashmap
  5. parcelable:所有实现parcelable接口的对象
  6. aidl:所有aidl接口本身也可以在aidl文件中使用

需要注意的是:在aidl中声明其他数据类型时,需要在前面加in(输入型参数)、out(输出型参数)、inout(输入输出型参数)

需要注意的是:除aidl所支持的数据类型外,如果要使用则必须导包,就算目标文件与当前文件在同一包下。

比如:

编写了两个文件,一个叫做 Book.java ,另一个叫做 BookManager.aidl,它们都在 com.xxx.aidldemo 包下 ,现在要在 .aidl 文件里使用 Book 对象,那么就必须在 .aidl 文件里面写上 import com.xxx.aidldemo.Book; 哪怕 .java 文件和 .aidl 文件就在一个包下。

2.定向tag:

表示在跨进程通信中数据的流向(流向是针对客户端的对象而言) 

in(输入型参数):客户端——>服务器

out(输出型参数):服务器——>客户端

inout(输入输出型参数):双向流通.

3.如果不包含非默认支持的数据类型,只需要编写一个AIDL文件,如果包含,通常需要写 n+1 个AIDL文件( n 为非默认支持的数据类型的种类数)
4.非默认支持数据类型的序列化操作

        1. 使数据类实现Parcelable接口

例:数据从客户端到服务端,可以在客户端对这个对象进行序列化(通常为实现Parcelable接口),将其中数据转化为序列化流,并传输到服务端内存中,再在服务端对这个数据进行反序列化操作,从而还原数据。

        2. 建立一个类,书写其成员变量,建立getter和setter并添加一个无参构造。令这个类implements Parcelable 。

需要注意的是:默认生成的模板类对象只支持为in的定向tag。因为默认生成的类中只有writeToParcel() 方法,如果要实现为 out 或者 inout 的定向 tag 的话,需要实现readFromParcel() 方法。

5.书写AIDL文件 

新建AIDL文件,AIDL文件大致分为两类:

一类是用来定义parcelable对象,以供其他AIDL文件使用AIDL中非默认支持的数据类型。

// Book.aidl//用于引入了一个序列化对象Book,供其他的AIDL文件使用//注意:Book.aidl与Book.java的包名应当是一样的package com.example.ipcclient; //注意parcelable是小写parcelable Book;

一类是用来定义方法接口,以供系统完成跨进程通信。

可理解为通信接口文件,需服务器端及客户端各一个定义,需内容相同。

// BookManager.aidlpackage com.example.ipcclient;//导入所需要使用的非默认支持数据类型的包import com.lypeer.ipcclient.Book; interface BookManager {     //所有的返回值前都不需要加任何东西,不管是什么数据类型    List getBooks();    Book getBook();    int getBookCount();     //传参时除了Java基本类型以及String,CharSequence之外的类型    //都需要在前面加上定向tag,具体加什么按需而定    void setBookPrice(in Book book , int price)    void setBookName(in Book book , String name)    void addBookIn(in Book book);    void addBookOut(out Book book);    void addBookInout(inout Book book);}

 

2.AIDL传递简单数据

1.服务端
        a.创建AIDL文件 

        IPerson.aidl

// IPerson.aidlpackage com.example.aidlserver;import com.example.aidlserver.AIDLService;interface IPerson {    String queryPerson(int num);}

创建完后进行build,生成IPerson.java文件

         b.自定义Service类

                i.继承Service类,定义一个PersonQueryBinder类用来继承IPerson.Stub类,实现了IPerson接口和IBinder接口。

                ii.实例化自定义的Stub类,重写onBind方法,返回binder对象。

        AIDLService.java

package com.example.aidlserver;public class AIDLService extends Service {    //实例化自定义的Stub类    private IBinder binder = new PersonQueryBinder();    private String[] names = {"第一个","第二个","第三个"};    private String query(int num)    {        if(num > 0 && num  
        c.在AndroidManifest.xml文件中注册Service
                                                                        
2.客户端

需要将服务端的aidl文件直接复制过来(包括其中的包),客户端的内容直接在Activity中完成即可。

流程如下:

        a.自定义的PersonConnection类实现ServiceConnection接口
        b.以PersonConnection对象作为参数,调用bindService绑定远程Service
bindService(service,conn,BIND_AUTO_CREATE);
        c.绑定远程Service的ServiceConnection并不能直接获取Service的onBind( )方法

                返回的IBinder对象,只能返回onBind()方法所返回的代理对象,所需处理如下:

iPerson = IPerson.Stub.asInterface(service);

代码:MainActivity.java
package com.example.aidlclient;public class MainActivity extends AppCompatActivity implements View.OnClickListener {    private EditText edit_num;    private Button btn_query;    private TextView txt_name;    private IPerson iPerson;    private PersonConnection conn = new PersonConnection();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //控件绑定        edit_num = findViewById(R.id.edit_num);        btn_query = findViewById(R.id.btn_query);        txt_name = findViewById(R.id.txt_name);        //绑定远程Service        Intent service = new Intent("LXY_aidl");        service.setPackage("com.example.aidlserver");//以PersonConnection对象作为参数,调用bindService绑定远程Service         bindService(service, conn, BIND_AUTO_CREATE);        btn_query.setOnClickListener(this);    }    @Override    public void onClick(View v) {        String number = edit_num.getText().toString();        int num = Integer.valueOf(number);        try {            txt_name.setText(iPerson.queryPerson(num));        } catch (RemoteException e) {            e.printStackTrace();        }        edit_num.setText("");    }//自定义的PersonConnection类实现ServiceConnection接口    private final class PersonConnection implements ServiceConnection {        public void onServiceConnected(ComponentName name, IBinder service) {            iPerson = IPerson.Stub.asInterface(service);        }        public void onServiceDisconnected(ComponentName name) {            iPerson = null;        }    }}
3.启动步骤及可能出现的bug

        启动步骤为:先启动服务端,再启动客户端

这个地方可能出现的bug如下: 

  • Android AIDL客户端调用服务端方法报错空指针,即找不到那个方法。

    报错为:java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.String com.example.aidlserver.ILanguage.queryLanguage(int)' on a null object reference

     解决方法:

            1.在客户端清单文件中配置服务端service的包路径

            2.服务端的onBind方法中,返回值不可为空,返回的值为binder对象;或自定义的继承了IPerson.Stub类的类的new 方法。

    • 服务端和客户端AIDL文件所在包路径不一致,报错异常为: 

      java.lang.SecurityException: Binder invocation to an incorrect interface

      解决方法:修改服务端service对应的完整包名,客户端应与服务端的一致。

      服务端:

       客户端:

      3.AIDL传递复杂数据

      1.基础操作:

              1.将writeToParcel和readFromPacel方法写入方法,将对象写入到包裹(parcel)中。

      需要注意的是:写入顺序与读取顺序需要相同

              2.在该类中添加一个名为CREATOR的static final属性 改属性需要实现:android.os.Parcelable.Creator接口

              3.从接口中写两个方法:

              a.createFromParcel(Parcel source)方法:实现从source创建出JavaBean实例

              b.newArray(int size):创建一个数组。

              4.定向tag

      2.服务端

      代码:Step1:创建aidl文件实现接口.
      1.Person.aidl
      // Person.aidlpackage com.example.aidl_p;parcelable Person;
      2. Salary.aidl
      // Salary.aidlpackage com.example.aidl_p;parcelable Salary;
      代码:Step2:分别建立类,需实现Parcelable接口,重写对应的方法
      1.Person.java
      package com.example.aidl_p;public class Person implements Parcelable {    private Integer id;    private String name;    public Person(Integer id,String name){        this.id = id;        this.name = name;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Integer getId() {        return id;    }    public void setId(Integer id) {        this.id = id;    }    protected Person(Parcel in) {    }    //写入数据到Parcel中的方法    @Override    public void writeToParcel(Parcel dest, int flags) {        //把对象所包含的数据写入到parcel中        dest.writeInt(id);        dest.writeString(name);    }    @Override    public int describeContents() {        return 0;    }    //必须提供一个名为CREATOR的static final属性 该属性需要实现    //android.os.Parcelable.Creator接口    public static final Creator CREATOR = new Creator() {        //从Parcel中读取数据,返回Person对象        @Override        public Person createFromParcel(Parcel in) {            return new Person(in.readInt(),in.readString());        }        @Override        public Person[] newArray(int size) {            return new Person[size];        }    };    //因为集合取出元素的时候是根据Person对象来取得    //需要重写hashCode()和equals()方法    @Override    public int hashCode() {        final int prime = 31;        int result = 1;        result = prime * result +((name == null)? 0 : name.hashCode());        return result;    }    //hashCode 自动生成    @Override    public boolean equals(Object o) {        if (this == o) return true;        if (o == null || getClass() != o.getClass()) return false;        Person person = (Person) o;        return Objects.equals(id, person.id) &&                Objects.equals(name, person.name);    }}
      2.Salary.java 
      package com.example.aidl_p;public class Salary implements Parcelable {    private String type;    private Integer salary;    public Integer getSalary() {        return salary;    }    public void setSalary(Integer salary) {        this.salary = salary;    }    public String getType() {        return type;    }    public void setType(String type) {        this.type = type;    }    protected Salary(Parcel in) {    }    public Salary(String type,Integer salary){        this.type = type;        this.salary = salary;    }    @Override    public int describeContents() {        return 0;    }    public static final Creator CREATOR = new Creator() {        //从Parcel中读取数据,返回Person对象        @Override        public Salary createFromParcel(Parcel in) {            return new Salary(in.readString(),in.readInt());        }        @Override        public Salary[] newArray(int size) {            return new Salary[size];        }    };    @Override    public void writeToParcel(Parcel parcel, int i) {        parcel.writeString(type);        parcel.writeInt(salary);    }    public String toString(){        return "工作:" + type + "    薪水: " + salary;    }}
      3.ISalary.aidl  获取工资信息的方法
      // ISalary.aidlpackage com.example.aidl_p;//无论在不在同一个包中都需要导包import com.example.aidl_p.Salary;import com.example.aidl_p.Person;interface ISalary { //定义一个Person对象作为传入参数    //接口中定义方法时,需要制定新参的传递模式,这里是传入,所以前面有一个in//获取工资信息    Salary getMsg(in Person owner);}
      4.AidlService.java 
      核心Service:

      定义一个SalaryBinder类继承Stub,从而实现ISalary和IBinder接口;定义一个存储信息的Map集合,

      重新onBind方法,返回SalaryBinder类的对象实例

      5.注册Service:
                                                                              
      3.客户端
      代码:Step1:将服务端的aidl复制过来。
      代码:Step2:定义一个ServciceConnection对象,重写对应方法,和普通数据的类似,接着bindService,然后再Button的点击事件中获取Salary对象并显示。
      MainActivity.java
      package com.example.aidl_kehu;public class MainActivity extends AppCompatActivity {    private ISalary salaryService;    private Button btnquery;    private EditText editname;    private TextView textshow;    private ServiceConnection connection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {            //返回的是代理对象,要调用这个方法            salaryService = ISalary.Stub.asInterface(iBinder);         }        @Override        public void onServiceDisconnected(ComponentName componentName) {            salaryService = null;        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        btnquery = findViewById(R.id.btnquery);        editname = findViewById(R.id.editname);        textshow = findViewById(R.id.textshow);        ActionBar actionBar = getSupportActionBar();        if(actionBar != null){            actionBar.hide();        }        Intent service = new Intent("android.intent.action.AIDLService");        service.setPackage("com.example.aidl_p");        bindService(service,connection, BIND_AUTO_CREATE);        btnquery.setOnClickListener(new View.OnClickListener() {            @SuppressLint("SetTextI18n")            @Override            public void onClick(View view) {                try {                    String name = editname.getText().toString();                    Salary salary = salaryService.getMsg(new Person(1,name));                    textshow.setText(name+salary.toString());                } catch (RemoteException e) {                    e.printStackTrace();                }            }        });    }    @Override    protected void onDestroy() {        super.onDestroy();        this.unbindService(connection);    }}

      4.AIDL总结 

      1.服务端

              a.创建aidl,创建同名类,在aidl中写parcelable接口。并创建aidl实现接口方法,且需要导包。

              b. 在类中生成set、get方法,创建对象,writeToParcel中把对象写进去,在createFromParcel中返回对象,创建toString() 方法用于输出。

              c.在Service中实现功能

      2.客户端

              a.复制服务端的aidl和类,在MainActivity中实现功能

上一篇:白撑浇水秘籍,轻松掌握植物浇水技巧,助力植物茁壮成长!

下一篇:php怎么发送qq邮箱?