Android平台必备技能(一)---进程间通信AIDL的应用详解

本文介绍了Android中的AIDL(Android Interface Definition Language),用于实现进程间通信。AIDL支持基本数据类型、List和Map,以及自定义的Parcelable对象。文章详细阐述了AIDL的语法、数据流向标记以及Android平台的各种IPC方式,重点对比了Binder与其他IPC机制的优缺点。同时,通过一个媒体文件分享的示例,展示了AIDL的实际应用,包括Server端和Client端的实现。此外,文中还提及了序列化与反序列化,特别是Parcelable接口在AIDL中的重要性,以及在实际使用中可能遇到的问题和解决策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一些必备的背景知识,理解以下知识将有助于编写AIDL通信流程。

1.  AIDL是什么?

    AIDL:Android Interface Definition Language,即Android接口定义语言。即Android平台上使用的IDL交互式数据语言,定义了Android平台IPC的模板。

2.  AIDL的语法?

    2.1)   AIDL文件以 .aidl 为后缀名;

    2.2)   支持八种基本数据类型:byte、char、short、int、long、float、double、boolean,以及String,CharSequence

    2.3)   List类型:List中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable。List可以使用泛型

    2.4)   Map类型:Map中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable。Map是不支持泛型的

    2.5)   AIDL定向tag:in,out,inout。添加在AIDL接口中表示数据通信的流向。

    in:   client -> server, 数据从客户端流向服务端

    out: server -> client,数据从服务端流向客户端

    inout:client <-> server,数据在服务端和客户端双向流通。

3.  Android平台IPC的几种方式

    3.1)   Socket(套接字)

    作为更通用的接口,传输效率低,主要用于不同机器或跨网络的通信;

    3.2)   Pipe(管道)

    在创建时分配一个page大小的内存,缓存区大小比较有限;

    3.3   MessageQueue(消息队列)

    消息队列:信息复制两次,额外的CPU消耗;不合适频繁或信息量大的通信;

    3.4   Anonymous shared memory(匿名共享内存)

    无须复制,共享缓冲区直接付附加到进程虚拟地址空间,速度快;但进程间的同步问题操作系统无法实现,必须各进程利用同步工具解决;

    3.5   Signal(信号量)

    不适用于信息交换,更适用于进程中断控制,比如非法内存访问,杀死某个进程等。比如系统log中常见的SIGABRT 6 C 由abort(3)发出的退出指令,SIGKILL 9 AEF Kill信号,SIGSEGV 11 C 无效的内存引用等等。

    3.6  Semaphore(信号量)

    常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

    3.7  Binder通信

    (1) 从性能的角度

    数据拷贝次数:Binder数据拷贝只需要一次,而管道、消息队列、Socket都需要2次,但共享内存方式一次内存拷贝都不需要;从性能角度看,Binder性能仅次于共享内存。

    (2) 从稳定性的角度

    Binder是基于C/S架构的,简单解释下C/S架构,是指客户端(Client)和服务端(Server)组成的架构,Client端有什么需求,直接发送给Server端去完成,架构清晰明朗,Server端与Client端相对独立,稳定性较好;而共享内存实现方式复杂,没有客户与服务端之别,需要充分考虑到访问临界资源的并发同步问题,否则可能会出现死锁等问题;从这稳定性角度看,Binder架构优越于共享内存。

    (3) 从安全的角度传统Linux

IPC的接收方无法获得对方进程可靠的UID/PID,从而无法鉴别对方身份;而Android作为一个开放的开源体系,拥有非常多的开发平台,App来源甚广,因此手机的安全显得额外重要;对于普通用户,绝不希望从App商店下载偷窥隐射数据、后台造成手机耗电等等问题,传统Linux IPC无任何保护措施,完全由上层协议来确保。

    (4) 语言层面的角度

    Android是基于Java语言(面向对象的语句),而对于Binder恰恰也符合面向对象的思想,将进程间通信转化为通过对某个Binder对象的引用调用该对象的方法,而其独特之处在于Binder对象是一个可以跨进程引用的对象,它的实体位于一个进程中,而它的引用却遍布于系统的各个进程之中。相比而言,Binder通信在安全性、性能方面都有比较明显的优势。

    Binder通信往往通过ioctl等方法跟内核空间的驱动进行交互:

 

图1

Binder的架构图:

 

图2

C/S架构设计:

 

图3

Android系统中Broadcast、ContentProvider、Message都能跨进程通讯,其根本原理都是Binder通信。可见Binder通信并非必须通过AIDL。

4.  序列化和反序列化

Android的进程都有独立的内存空间,相互间不能访问。想要在进程间数据通信,就需要将数据做序列化和反序列化。Android中对数据序列化有两种方法:一种是实现Serializable接口另一种是实现Parcelable接口。Parcelable是android特有的序列化API,它的出现是为了解决Serializable在序列化的过程中消耗资源严重的问题,但是因为本身使用需要手动处理序列化和反序列化过程,会与具体的代码绑定,使用较为繁琐,一般只获取内存数据的时候使用。

简单介绍下Parcelable的两个过程:序列化、反序列化。

序列化:

@Override

publicvoid writeToParcel(Parcel dest, int flags) {

}

反序列化:

classBean {

}

publicstatic final Creator< Bean > CREATOR = new Creator< Bean >() {

        @Override

        public User createFromParcel(Parcelsource) {

            return null;

        }

        @Override

        public User[] newArray(int size) {

            return new Bean [size];

        }

};

5、AIDL的使用示例

在App 1中分享一个媒体文件(例如MP3)给另一个App 2。App 1中可以播放这个媒体文件,展示上传文件进度。App 2可以播放传输过来的媒体文件。列举下Server端和Client端需要做的事情:

    a) AIDL通信过程中,Server端需要做什么?

    创建aidl文件以及数据通信类型,确认数据流向,后台Service,在Service中埋入桩(Stub),以及在AndroidManifest.xml中声明该Service。

    b) AIDL通信过程中,Client端需要做什么?

    创建aidl文件以及数据通信类型(和Server端要保持一致),在activity或者适当位置bindService,bindService中的参数ServiceConnection,调用aidl接口函数传递数据。

    值得注意的是,Client端不是必须要有Activity来传递数据,很多例子中都以Activity来演示,一个是方便看到数据通信结果,另一个是Activity有完整的生命周期,binder通信可以选择在onCreate中bindService,在onStop中unbindService,这样能有效回收资源。

5.1 明确Client端和Server端

   从需求关系看:

    1)  App 1作为数据提供方,需要源源不断的将数据传给App 2;

    2)   App 2作为页面(Activity)结果展示,更适合作客户端。

    定义App 1为Server端, App 2作为Client端。分别创建App 1和App 2,以及对应的MainActivity,相关的aidl文件,App 1创建Service,以及对应的桩(Stub)。

(ps:不过,如果反过来App 1作为客户端,主动调用AIDL接口获取App 2传过来的数据,思路也是通的。不过数据流向需要调整。)

5.2 确定接口以及数据流向

媒体文件的传递,确定接口:

// 通知文件传输流程开始

void onMediaShareStart(in String name);

//文件分段传输数据

void onMediaSharing(in MediaData data);

//通知文件传输结束

void onMediaShareFinish();

数据从当前页面上传到server端,数据流向为Client端到Server端,接口参数配置in。

5.3创建AIDL文件

先从Server端开始。创建aidl文件:IMediaShareInterface.aidl、MediaData.aidl和MediaData.java。

//IMediaShareInterface.aidl

package com.cloudyhill.mediashare;

// Declare any non-default types here withimport statements

import com.cloudyhill.mediashare.MediaData;

interface IMediaShareInterface {

    void onMediaShareStart(in String name);

    void onMediaSharing(in MediaData data);

    void onMediaShareFinish();

}

MediaData.aidl:

packagecom.cloudyhill.mediashare;

// Declare anynon-default types here with import statements

parcelable MediaData;

实现序列化的MediaData类,即文件MediaData.java,注意类的包名和类名和MediaData.aidl保持一致,否则会报错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值