Andorid总结 - AIDL

使用AIDL的必要条件是你允许来自不同应用的client来访问你的service做IPC的操作,并且需要处理多线程的情况。

如果你不要做跨进程的IPC,那么你应该使用“Extending the Binder class”方法,参考Andorid总结 - Bound Services

如果需要跨进程IPC但是不会有多线程的操作,那么你应该使用“Using a Messenger”方法,参考Andorid总结 - Bound Services

在使用AIDL时,client与service在同一进程和不在同一进程的区别:

  • 在相同进程中,service中的AIDL方法会在调用者所在的线程中执行。
  • 在不同进程中,远程进程的调用会从维护在本进程中的一个线程池中随机分配一个线程来执行。AIDL的接口实现必须是线程安全的。
  • oneway 关键字用来修饰远程调用的行为。如果使用的话,呢么远程调用就不会被block了;它之后发送数据并立马返回。 oneway对本地调用不起作用,调用依旧是同步的。

定义AIDL接口

你必须要定义AIDL接口在 “.aidl”文件中,语法跟Java类似。“.aidl”可以通过Android Studio来帮助创建,Android Studio会默认创建一个文件夹来保存.aidl的文件。

在应用程序编译之后,Android SDK tools 会根据”.aidl”生成一个IBinder的接口,这个接口保存在build目录下。service必须实现IBinder,然后把这个IBinder传给client调用。

具体步骤如下:

  1. 创建.aidl文件
    “.aidl”文件中定义一个接口,接口里的方法提供给client调用。
    AIDL使用很简单的Java语法,里面什么的方法可以带有参数和返回值。参数和返回值的类型可以为任意的类型,甚至可以用AIDL生成的接口做参数。只能定义方法,不能有变量。
    AIDL中可以用的默认类型有:

    • String
    • CharSequence
    • List
    • Map

    使用额外的数据类型时,必须使用import来导入,即使在同一个包中。

// IRemoteService.aidl
package com.example.android;

// Declare any non-default types here with import statements

/** Example service interface */
interface IRemoteService {
    /** Request the process ID of this service, to do evil things with it. */
    int getPid();

    /** Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}

编译完成后的目录看似这样:
这里写图片描述
这里写图片描述

2.实现接口

如上图,当编译完成后,Android SDK tools会给我们在generated/source中生成对应的java接口文件。生成的接口包含了一个叫“Stub”的子类,比如“YourServiceInterface.Stub”,这个子类同事也继承了Binder,而我们的Servcie就是要实现这个Stub子类,作为Binder来传递给client使用。

private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
    public int getPid(){
        return Process.myPid();
    }
    public void basicTypes(int anInt, long aLong, boolean aBoolean,
        float aFloat, double aDouble, String aString) {
        // Does nothing
    }
};

在实现AIDL接口时,有几个小规格要注意:

  • 调用接口不保证在主线程执行,所以需要考虑启动时的多线程和建立时的线程安全。
  • 默认,RPC调用是同步的。所以如果请求比较耗时的话,请使用子线程来调用。
  • client端不用收到任务异常消息。

    1. 把接口暴露给clients
      只需在onBinder()函数中把上一步的实现了Stub的对象mBinder 返回给clients。
public class RemoteService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public IBinder onBind(Intent intent) {
        // Return the interface
        return mBinder;
    }

    private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
        public int getPid(){
            return Process.myPid();
        }
        public void basicTypes(int anInt, long aLong, boolean aBoolean,
            float aFloat, double aDouble, String aString) {
            // Does nothing
        }
    };
}

而client的onServiceConnected() callback 就会接受到这个mBinder 对象。接收到之后通过调用 YourServiceInterface.Stub.asInterface(service) 把mBinder转换为 YourServiceInterface类型. For example:

IRemoteService mIRemoteService;
private ServiceConnection mConnection = new ServiceConnection() {
    // Called when the connection with the service is established
    public void onServiceConnected(ComponentName className, IBinder service) {
        // Following the example above for an AIDL interface,
        // this gets an instance of the IRemoteInterface, which we can use to call on the service
        mIRemoteService = IRemoteService.Stub.asInterface(service);
    }

    // Called when the connection with the service disconnects unexpectedly
    public void onServiceDisconnected(ComponentName className) {
        Log.e(TAG, "Service has unexpectedly disconnected");
        mIRemoteService = null;
    }
};

调用 IPC 方法

跟Bound Sercie类似,唯一需要注意的就是调用方法的时候,需要补货一个 异常 DeadObjectException。当连接断开的时候会抛出这个异常。

在IPC中传递对象

可以在IPC中传递对象,但是这个对象必须实现Parcelable 接口。快速实现Parcelable 可以通过Android Studio的插件“android-parcelable-intellij-plugin”

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值