Android AIDL详解

转载请注明来自:http://blog.csdn.net/ly20116/article/details/51112833

一、AIDL定义

AIDL(Android Interface Definition Language),它允许你定义客户端与服务端达成一致的程序接口使用进程间通信( interprocess communication ,IPC)相互交流。

在Android上面,一个进程不能正常的访问另一个进程的内存。 所以说,他们需要分解他们的对象为操作系统可以理解的基本单位,然后为你把这些对象按次序跨越进程边界 书写这些代码是单调冗长的,所以android使用AIDL为你处理这个问题。

AIDL IPC机制是面向接口的,它是使用代理类在客户端和实现端传递数据

注意:使用AIDL只有在你允许来自不同应用的客户端跨进程通信访问你的service,并且想要在你的service种处理多线程的时候才是必要的。

二、AIDL接口的创建与使用

你必须在一个.aidl文件中使用java编程语言语法定义你的AIDL接口,然后在提供service的应用中和任何绑定到这个service的应用中的源代码中(在src目录下)保存它

当你编译包含.aidl文件的应用时,Android SDK工具基于这个.aidl文件生成一个IBinder接口,并且把它保存到项目的gen目录吓 service必须恰当的实现这个IBinder接口 之后客户端应用可以绑定到这个服务上,然后从IBinder调用方法来执行IPC

1、创建AIDL文件

IServiceAidlInterface.aidl:

// IServiceAidlInterface.aidl
package com.yang.serviceaidl;

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

interface IServiceAidlInterface {
    /**
     * 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);

    void setData(String data);//自定义方法声明
}

默认的,AIDL支持下面数据类型

  • Java语言中的所有基本数据类型(比如int、long、char、boolean等等)
  • String
  • CharSequence
  • List

    List中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是你定义的parcelable
    List可以使用范型(例如,List) 接收端的实际类经常是一个ArrayList,尽管方法是使用List接口生成的
    
  • Map

    Map中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是你定义的parcelable范型map是不被支持的(比如这种形式Map) 接收端的实际类经常是一个HashMap,尽管方法是使用Map接口生成的
    

对于上述类型之外的类型,你必须声明 import ,即使在同一个包内

简单的保存你的.aidl文件在你工程的src目录下,当你build你的应用时,SDK工具在你工程的gen目录下生成IBinder接口文件 生成的文件名字与.aidl名字匹配,但是是以.java为扩展名(例如IRemoteService.aidl对应为IRemoteService.java)

2、实现接口
在你定义的Service中onBind方法

 @Override
    public IBinder onBind(Intent intent) {

        return new IServiceAidlInterface.Stub() {
            @Override
            public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

            }

            @Override
            public void setData(String data) throws RemoteException {
                AppService.this.data=data;
            }
        };
    }

Stub类(如IServiceAidlInterface.Stub())是它父类的抽象实现,并且声明了.aidl中所有的方法,
Stub的asInterface()方法,它是用来接收一个IBinder(通常IBinder传递给客户端的onServiceConnected()回调方法)并且返回一个Stub接口的实例。

注意事项:

  • 调用不保证在主线程中执行
  • 默认的,RPC调用是同步的。 如果你知道service需要花费一些时间来完成请求,你就不应该从activity的主线程中调用它,因为它可能使得应用没有响应(Android也许会显示一个ANR的对话框),通常你应该在客户端中一个单独的线程调用它
  • 抛出的异常不会返回给调用者

    3、客户端获取接口

如果是跨应用调用Service,那么你应该在另一个应用中一模一样的AIDL文件(包名,类名相同等等),。如下图结构:
这里写图片描述

在androidapp工程中建立一个与app工程相同的AIDL文件,包括包名。
跨应用启动Service的Intent(显示调用方法);

Intent serviceIntent=new Intent();
serviceIntent.setComponent(new ComponentName("com.yang.serviceaidl","com.yang.serviceaidl.AppService"));

参数说明:

 1. 包名
 2. 类名

//启动服务   startService(serviceIntent);
//关闭服务  stopService(serviceIntent);
//绑定服务   bindService(serviceIntent,this,Context.BIND_AUTO_CREATE);
//解绑服务    unbindService(this);   

在androidapp中调用给接口,在MainActivity(实现了ServiceConnection接口)中onServiceConnected()方法中

 private IServiceAidlInterface binder=null;

  @Override
    public void onServiceConnected(ComponentName name, IBinder service) {

//        binder= (IServiceAidlInterface) service;  //错误的
        binder=IServiceAidlInterface.Stub.asInterface(service);
    }

类似于Service的绑定通信。

传递数据

if(binder!=null){
           try {
                       binder.setData(data.getText().toString());
               } catch (RemoteException e) {
                        e.printStackTrace();
               }
 }

总结:调用IPC方法步骤:

  1. 在项目中的src目录下面导入.aidl文件
  2. 声明一个IBinder接口(基于AIDL生成的)的实例
  3. 实现ServiceConnection
  4. 调用Context.bindService(),传递到你的ServiceConnection实现中
  5. 在你的onServiceConnected()实现中,你会收到一个IBinder实例(称为服务端) 调用YourInterfaceName.Stub.asInterface((IBinder)service)把返回值映射到YourInterface类型上面
  6. 调用你接口中定义的方法 你应该捕获当连接损坏时抛出的DeadObjectException异常,这是远程方法唯一会抛出的异常
  7. 使用你接口的实例调用Context.unbindService()来断开连接

三、跨进程传递对象

果你想通过IPC接口把一个类从一个进程传递到另一个进程中,那么是可以的。 然而,你必须保证为你的类而写的代码也是对IPC通道另一端是可用的,并且你的类必须支持Parcelable接口 支持Parcelable接口是很重要的,因为它允许Android系统把对象分解为可以被组织跨进程传输基本单元

为了建立一个支持Parcelable协议的类,你必须遵守下面的规则:

  1. 要实现Parcelable接口
  2. 实现writeToParcel,它是用来把对象的当前状态写入到一个Parcel对象中的。
  3. 在你的类中添加一个叫CREATOR的静态域,它要实现Parcelable.Creator接口
  4. 最后,建立一个.aidl文件声明你的parcelable类(如下面的Rect.aidl所示)
    如果你使用一个定制的构建过程,不要构建.aidl文件。与C语言中的头文件类似,.aidl文件不会被编译

AIDL使用代码中的这些域和方法封装传送和解读你的对象

Rect.aidl文件:

package android.graphics;

// Declare Rect so AIDL can find it and knows that it implements
// the parcelable protocol.
parcelable Rect;

Rect类:

public final class Rect implements Parcelable {
    public int left;
    public int top;
    public int right;
    public int bottom;

    public static final Parcelable.Creator<Rect> CREATOR = new
Parcelable.Creator<Rect>() {
        public Rect createFromParcel(Parcel in) {
            return new Rect(in);
        }

        public Rect[] newArray(int size) {
            return new Rect[size];
        }
    };

    public Rect() {
    }

    private Rect(Parcel in) {
        readFromParcel(in);
    }

    public void writeToParcel(Parcel out) {
        out.writeInt(left);
        out.writeInt(top);
        out.writeInt(right);
        out.writeInt(bottom);
    }

    public void readFromParcel(Parcel in) {
        left = in.readInt();
        top = in.readInt();
        right = in.readInt();
        bottom = in.readInt();
    }
}

总结

AIDL是android接口定义语言,主要是android中用来解决进程间通信(interprocess communication ,IPC)的。
它和绑定服务通信实现类似,不过是绑定服务通信时我们继承Binder实现的接口MyBinder变成了AIDL实现。

AIDL实例下载链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值