AIDL实现跨进程Service绑定
# 1. 组件间通信方式
已知:在Service中,onBind()方法的返回值可以被Activity获得,即Activity与Service共有一个IBinder类型的对象。
结论:开发人员可以在Service中自定义IBinder的实现类,并在该类中定义若干方法,当Activity获得该实现类的对象时,即可调用这些方法。
矛盾:IBinder的实现类的相关业务可能与Activity发送的Intent、Service的生命周期等存在密切关系,使用Service的内部类定义更合适,但使用内部类则无法让Activity知晓该实现类的数据类型。
解决方法:使用接口定义Activity需要让Service完成的方法。
# 2. 进程间通信方式
进程间通信模式是组件间通信的“高级”应用方式,与一般组件间通信的区别在于:接口需要使用AIDL定义
由于存在2个应用程序进行通信,提供服务的应用程序通常被称之为“服务端”,而调用它的接口的方法的应用程序则被称之为“客户端”。
# 3. AIDL简介
AIDL表示"Android接口定义语言":Android Interface Definition Language.
用于生成可以在Android设备上两个进程间通信的代码
# 3.1 AIDL接口
使用JAVA中创建接口的方式即可创建AIDL的接口,区别在于:
- AIDL的接口的源文件扩展名是
.aidl
,而一般接口的源文件扩展名是.java
; - AIDL的接口不允许使用public或任何访问权限修饰符去修饰该接口,它默认即被修饰为public。
AIDL接口编译 ==> .java ==> .class
# 3.2 AIDL远程绑定Service
使用AIDL与一般绑定服务的区别如下:
- 【服务端】使用AIDL接口;
- 【服务端】创建AIDL接口的内部类Stub的子类对象,并将其作为Service中onBind()的返回值;
- 【服务端】必须配置Service是可以隐式激活的;
- 【客户端】将服务端的AIDL文件复制到客户端;
- 【客户端】在ServiceConnection的onServiceConnected()中,使用AIDL接口的Stub的asInterface()方法,将参数IBinder转换为AIDL接口的对象。
在开发工具生成的AIDL接口的JAVA源文件中,定义了名为Stub的内部类,继承了android.os.Binder,并实现了AIDL的接口,因此,开发人员在创建Service中的IBinder的实现类时,仅需继承该Stub类即可
由开发人员定义的AIDL接口中的抽象方法,都被定义为抛出远程异常(android.os.RemoteException),在实现这些抽象方法时需要处理
在AIDL接口的Stub内部类中,存在asInterface(IBinder obj)方法,用于将IBinder对象转换为AIDL接口的实现类对象,因此,在绑定Service的组件中,可通过该方法得到AIDL接口的实现类对象。
# 3.3 服务端开发步骤
[1] 开发AIDL接口源文件,并确保扩展名是.aidl(如果先创建的*java源文件后改名,则需刷新);
[2] 在Service中开发AIDL接口的实现类,并实现AIDL接口中定义的抽象方法;
[3] 实现Service类中的onBind()方法,并将AIDL的实现类的对象作为该方法的返回值;
[4] 注册Service类,并配置<intent-filter>
;
[5] 部署服务端应用程序到设备上。
# 3.4 客户端开发步骤
[1] 将服务端的AIDL相关文件复制到客户端中,注意:相关文件的包名、类名不允许修改;
[2] 开发ServiceConnection接口中的实现类;
[3] 使用隐式意图绑定服务端的Service;
[4] 在ServiceConnection接口中的实现类的onServiceConnected()方法中,通过AIDL的内部类Stub的asInterface()方法,将IBinder对象转换为ADIL接口的对象。
# 3.5 注意事项
# 4. 建立AIDL
AndroidStudio的aidl文件默认放在src/main/aidl目录下,aidl目录和java目录同级别。
在模块或者项目下,右键新建aidl文件夹,AS自动识别并放到与java同级别下
在java目录上右键,创建一个aidl文件,此文件会默认生成到aidl目录下。
同时必须要指明包名,包名必须和java目录下的包名一致。
Model类必须要实现Parcelable接口!
如果aidl需要使用Model类,必须要import进来,不然会找不到。
然后Builde一下,此时就可以实现接口了。