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

这篇具有很好参考价值的文章主要介绍了Android:AIDL简单介绍+传递简单数据+传递复杂数据。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

对于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() 方法。

aidl传递数据,android,学习,java,开发语言

5.书写AIDL文件 

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

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

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

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

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

// BookManager.aidl
package com.example.ipcclient;
//导入所需要使用的非默认支持数据类型的包
import com.lypeer.ipcclient.Book;
 
interface BookManager {
 
    //所有的返回值前都不需要加任何东西,不管是什么数据类型
    List<Book> 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);
}

aidl传递数据,android,学习,java,开发语言 

2.AIDL传递简单数据

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

        IPerson.aidl

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

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

aidl传递数据,android,学习,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 < 6){
            return names[num - 1];
        }
        return null;
    }

    @Override
    public IBinder onBind(Intent intent) {
//重写onBind方法,返回binder对象。
//        return new PersonQueryBinder();
        return binder;
    }
    //定义一个PersonQueryBinder类用来继承IPerson.Stub类,实现了IPerson接口。
    private final class PersonQueryBinder extends IPerson.Stub {

        public String queryPerson(int num) throws RemoteException {
            return query(num);
        }
    }
}
        c.在AndroidManifest.xml文件中注册Service
        <service android:name=".AIDLService"
            android:exported="true">
            <intent-filter>
                <action android:name="任意名即可,如:LXYaidl" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </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);

aidl传递数据,android,学习,java,开发语言

代码: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

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

aidl传递数据,android,学习,java,开发语言

这个地方可能出现的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的包路径

aidl传递数据,android,学习,java,开发语言

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

aidl传递数据,android,学习,java,开发语言

aidl传递数据,android,学习,java,开发语言

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

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

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

服务端:aidl传递数据,android,学习,java,开发语言

 客户端:

aidl传递数据,android,学习,java,开发语言

aidl传递数据,android,学习,java,开发语言

3.AIDL传递复杂数据

1.基础操作:

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

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

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

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

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

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

        4.定向tag

2.服务端

aidl传递数据,android,学习,java,开发语言

代码:Step1:创建aidl文件实现接口.
1.Person.aidl
// Person.aidl
package com.example.aidl_p;
parcelable Person;
2. Salary.aidl
// Salary.aidl
package 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<T>接口
    public static final Creator<Person> CREATOR = new Creator<Person>() {
        //从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<Salary> CREATOR = new Creator<Salary>() {
        //从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.aidl
package 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:
        <service android:name=".AidlService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.AIDLService" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </service>
3.客户端

aidl传递数据,android,学习,java,开发语言

代码: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实现接口方法,且需要导包。

aidl传递数据,android,学习,java,开发语言

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

        c.在Service中实现功能

2.客户端

        a.复制服务端的aidl和类,在MainActivity中实现功能文章来源地址https://www.toymoban.com/news/detail-831555.html

到了这里,关于Android:AIDL简单介绍+传递简单数据+传递复杂数据的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [Android AIDL系列 1] 手动编译aidl文件,生成Java、C++[android]、C++[ndk]、Rust接口

    AIDL文件在Android系统上应用广泛,和底层的Binder机制紧密关联。 在Android源码或者Android Studio中通常是自动编译aidl文件,生成对应语言的接口文件。 做应用层Java开发,aidl和binder封装的比较“干净”,不用太多的涉及binder的调用细节,也不用太关心aidl的编译过程。 如果是做中

    2024年02月08日
    浏览(44)
  • Android AIDL基本使用

    AIDL是Android多进程通讯方式一种。 如要使用 AIDL 创建绑定服务,请执行以下步骤: 创建 .aidl 文件 此文件定义带有方法签名的编程接口。 实现接口 Android SDK 工具会基于您的  .aidl  文件,使用 Java 编程语言生成接口。此接口拥有一个名为  Stub  的内部抽象类,用于扩展  B

    2024年02月09日
    浏览(37)
  • Android:AIDL实战详解

    AIDL:Android Interface Definition Language AIDL是为了实现进程间通信而设计的Android接口语言 Android进程间通信有多种方式,Binder机制是其中最常见的一种 AIDL的本质 就是基于对Binder的运用从而实现进程间通信 这篇博文从实战出发,用一个尽可能精简的Demo,实现两个App (也是两个进程:

    2024年02月08日
    浏览(40)
  • Android studio 无法创建AIDL文件

    Android studio 创建AIDL文件的时候 提示是灰色的无法创建 处理方法在app下面的build.gradle中的buildFeatures 添加 aidl = true 这个是 kotlin的写法,如果是使用的旧项目修改下格式就行

    2024年01月25日
    浏览(39)
  • Android 使用AIDL传输超大型文件

    最近在写车载Android的第5篇视频教程「AIDL的实践与封装」时,遇到一个有意思的问题,能不能通过AIDL传输超过 1M 以上的文件? 我们先不细究,为什么要用AIDL传递大文件,单纯从技术的角度考虑能不能实现。众所周知,AIDL是一种基于Binder实现的跨进程调用方案,Binder 对传输

    2024年02月10日
    浏览(52)
  • android aidl进程间通信封装通用实现

    接上一篇的分析,今天继续 aidl复杂流程封装-CSDN博客 今天的任务就是将代码梳理下放进来 1 项目gradle配置:    需要将对应的代码放到各自的目录下,这里仅贴下关键内容,细节可以下载代码慢慢看     sourceSets {         main {             manifest.srcFile \\\'src/main/AndroidManife

    2024年02月22日
    浏览(37)
  • Android Binder——APP中AIDL实现(十九)

            AIDL(Android Interface Definition Language)其实就是对 Binder 通信的一个封装,方便在开发中对 Binder 通信的使用,这里我们就从头开始来看一下 AIDL 通信的创建过程。         通过 Android Studio 的 File -New - AIDL 的方式就会生成对应包名的 aidl 文件。即 aidl 文件要与应用

    2024年04月28日
    浏览(28)
  • 深入解析Android AIDL:实现跨进程通信的利器

    Android Interface Definition Language (AIDL) 是一种Android系统中的跨进程通信机制。AIDL允许一个应用程序的组件与另一个应用程序的组件通信,并在两者之间传输数据。 AIDL的主要作用是帮助不同进程间共享数据和服务,让他们能够互相调用。例如,在开发一个多功能的音乐播放器时,

    2024年02月19日
    浏览(43)
  • android aidl进程间通信封装通用实现-用法说明

    接上一篇:android aidl进程间通信封装通用实现-CSDN博客 该aar包的使用还是比较方便的 一先看客户端 1 初始化 2 发送事件:  就是通过json的形式将参数包裹进来,另一端统一解析  唯一标志位:KEY_CLIENT_REQUEST_AUTHOR 是必须要加的,不然区分不出来是那个客户端 二再看服务端

    2024年02月20日
    浏览(34)
  • Android Binder常用案例使用分析,跨进程通信aidl

    service组件的binderService获取binder通信。 servicemanager.getService方法获取相关服务。 本质上都是IBinder通信。 客户端:使用intent,启动服务端的service,使用binderservice,在onServiceConnected回调方法中获取服务端的实际binder对象。使用aidl中的接口调用服务端的方法即可。 服务端:定义

    2024年02月07日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包