AIDL进程间通信之AIDL

转载请标明出处:http://blog.csdn.net/u013254166/article/details/78612405
本文出自: rhino博客 

        本篇主要讲解Android进程间通信手段——AIDL,即AndroidInterface Definition Language(Android接口定义语言)。文章没有粘贴太多的代码,最后面有源码的下载链接。

1. 简述

        为了实现进程间通信,尤其是在涉及多进程并发情况下的进程间通信。

        要进行跨进程通信的话,其实我们还有其他的一些选择,比如BroadcastReceiver , Messenger 等。但是 BroadcastReceiver 占用的系统资源比较多,如果是频繁的跨进程通信的话显然是不可取的;Messenger进行跨进程通信时请求队列是同步进行的,无法并发执行,在多进程的情况下不适用。这种时候就需要使用AIDL 了。

        官方文档特别提醒我们何时使用AIDL是必要的:“只有当你允许来自不同的客户端访问你的服务并且需要处理多线程问题时你才必须使用AIDL,…”。

2. 语法

        其实AIDL这门语言非常的简单,基本上它的语法和Java 一样,只是在一些细微处有些许差别。

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

        数据类型:AIDL默认支持一些数据类型,在使用这些数据类型的时候是不需要导包的。但是除了这些类型之外的数据类型,在使用之前必须导包,就算引用目标文件与当前正在编写的.aidl 文件在同一个包下(在 Java 中不需要)。默认支持的数据类型包括:

                Java中的八种基本数据类型,包括 byte,short,int,long,float,double,boolean,char。

                String 类型。

                CharSequence类型。

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

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

        定向tag:表示了在跨进程通信中数据的流向,用于修饰参数

                in 表示数据只能由客户端流向服务端,表现为服务端将会接收到一个那个对象的完整数据,但是客户端的那个对象不会因为服务端对传参的修改而发生变动。

                out 表示数据只能由服务端流向客户端,表现为服务端将会接收到那个对象的参数为空的对象,但是在服务端对接收到的空对象有任何修改之后客户端将会同步变动。

                inout 则表示数据可在服务端与客户端之间双向流通,服务端将会接收到客户端传来对象的完整信息,并且客户端将会同步服务端对该对象的任何变动。(与java一样)

        两类AIDL文件:

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

                第二类:用来定义方法接口,以供系统使用来完成跨进程通信的。

        注:所有的非默认支持数据类型必须通过第一类AIDL文件定义才能被使用。

3. 使用实例

3.1 新建AIDL文件

        右键module名>New>AIDL>AIDLFile。

        

        新建aidl文件后,比起以前多了一个叫做aidl 的包,而且他的层级是和java 包相同的,并且aidl 包里默认有着和java 包里默认的包结构。如果AS版本较低,可能不会自动生成,可以手动新建包结构。

        

        Person.aidl定义前面说到的第一类文件,由parcelable修饰,供PersonManager引用。

        PersonManager.aidl定义前面说到的第二类文件,主要是定义接口。

        Person.java定义Person.aidl的具体内容,需要实现Parcelable接口。默认生成的模板类的对象只支持为in的定向 tag。因为默认生成的类里面只有 writeToParcel() 方法,而如果要支持为out 或者inout 的定向 tag 的话,还需要实现readFromParcel() 方法,(这个方法Parcelable 接口没有)。

3.2 找不到文件

        Gradle默认是将java 代码的访问路径设置在java 包下的,这样一来,如果java 文件是放在aidl 包下的话那么理所当然系统是找不到这个java 文件的。那应该怎么办呢?

        a. 修改build.gradle 文件:在 android{} 中间加上下面的内容:

                sourceSets {

                        main {

                                java.srcDirs= ['src/main/java', 'src/main/aidl']

                        }

                }

        b. 把 java 文件放到java 包下去:把 Person.java 放到 java 包里任意一个包下,保持其包名不变,与 Person.aidl 一致。只要它的包名不变,Person.aidl就能找到 Person.java,而只要 Person.java 在java 包下,那么系统也是能找到它的。但是这样做的话也有一个问题,就是在移植相关.aidl 文件和 .java 文件的时候没那么方便,不能直接把整个aidl 文件夹拿过去完事儿了,还要单独将.java 文件放到 java 文件夹里去。

3.3 移植aidl相关文件

        在客户端和服务端中都有我们需要用到的.aidl文件和其中涉及到的.java文件。因此不管在哪一端写的这些东西,写完之后我们都要把这些文件复制到另一端去。

        

        当然如果是在同一app就不需要移植了。

3.4 编写服务端代码 AIDLService.java

        在服务端实现AIDL中定义的方法接口的具体逻辑,在onBind回调中返回该接口mPersonManager,然后客户端bind该服务器的时候,通过回调能拿到mPersonManager实例,从而可以通过mPersonManager实例调用通信接口,从而达到跨进程通信的目的。     

        privatefinal PersonManager.Stub mPersonManager = new PersonManager.Stub(){

                //这里实现PersonManager的接口

        }

        ……

        public IBinderonBind(Intent intent) {

                return mPersonManager;

        }

 

        AndroidManifest.xml

        <serviceandroid:name=".AIDLService">

                <intent-filter>

                        <action android:name="com.rhino.aidl.test" />

                </intent-filter>

        </service>

3.5 编写客户端代码 MainActivity.java

        privateServiceConnection mServiceConnection = new ServiceConnection() {

                @Override

                public void onServiceConnected(ComponentName name, IBinder service) {

                        // 将服务端的Binder对象转换为客户端所需要的接口对象,

                        // 该过程区分进程,如果进程一样,就返回服务端Stub对象本身,

                        // 否则呢就返回封装后的Stub.Proxy对象。

                        mPersonManager = PersonManager.Stub.asInterface(service);

                        mIsBound = true;

                }

                @Override

                public void onServiceDisconnected(ComponentName name) {

                        mIsBound = false;

                }

        };

        // 启动服务

        privatevoid attemptToBindService() {

                Intent intent = new Intent();

                intent.setAction("com.rhino.aidl.test");

                intent.setPackage("com.rhino.aidlserver");

                bindService(intent, mServiceConnection,Context.BIND_AUTO_CREATE);

        }


        最后附上源码下载链接,点击下载。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AIDLAndroid Interface Definition Language)是Android中用于进程间通信(IPC)的一种机制。它允许不的应用程序或在不同的进程进行通信。下面是对AIDL进程间通信的详细讲解: 1. 定义接口:首先,你需要创建一个AIDL接口,该接口包含用于进程间通信的方法和数据类型。AIDL接口文件通常以`.aidl`为后缀名,放置在`src/main/aidl`目录中。在接口中定义的方法参数和返回值只能使用支持的数据类型、其他AIDL接口或Parcelable对象。 2. 实现接口:在服务端应用程序中,你需要实现AIDL接口。实现类需要继承自AIDL接口生成的抽象类,并实现其中的方法。这些方法将用于处理客户端发起的远程调用请求。 3. 注册接口:在服务端应用程序的`AndroidManifest.xml`文件中,使用`<service>`标签注册你的服务,并通过`android:process`属性指定所在的进程。确保在`<intent-filter>`标签中包含正确的action,使得客户端能够找到并与你的服务进行绑定。 4. 创建客户端:在客户端应用程序中,你需要绑定到服务端应用程序中的服务。使用`ServiceConnection`接口来管理与服务的连接和断开连接。当连接成功后,你可以通过AIDL接口提供的方法与服务进行通信。 5. 调用方法:在客户端与服务端建立连接后,你可以通过AIDL接口提供的方法调用服务端的功能。这些方法调用将跨越进程边界执行,并将结果返回给客户端。 6. 处理并发:在处理AIDL进程间通信时,需要注意并发性和线程安全性。多个客户端可能同时访问服务端,因此需要合理地处理并发情况,以保证数据的一致性和安全性。 总结来说,AIDL进程间通信是通过定义接口、实现接口、注册接口、创建客户端和调用方法来实现的。这种机制允许不同进程的应用程序之间进行通信,并共享数据和功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值