Android--AIDL学习



1、AIDL:Android Interface Definition Language,即Android接口定义语言。

Android使用AIDL来支持Service和应用程序组件之间的进程间通信(IPC),包括运行在不同应用程序或者单独进程中的组件。使得Service具有跨进程便捷来支持多个应用程序的能力。

在进程间传递对象,需要将数据解析为OS级别的原语,这里通过实现Parcelable接口来实现。(http://blog.csdn.net/woliuyunyicai/article/details/45286731

2、建立AIDL的步骤:

(1)在Eclipse Android工程的Java包目录中建立一个扩展名为aidl的文件。该文件的语法类似于Java代码,但会稍有不同。

(2)如果aidl文件的内容是正确的,ADT会自动生成一个Java接口文件(*.java)。

(3)建立一个服务类(Service的子类)。

(4)实现由aidl文件生成的Java接口。

(5)在AndroidManifest.xml文件中配置AIDL服务,尤其要注意的是,<action>标签中android:name的属性值就是客户端要引用该服务的ID,也就是Intent类的参数值。

3、AIDL服务支持的数据类型:

1)Java简单类型(int、char、boolean等)。不需要import。

2)String和CharSequence;不需要import

3)List和Map。但List和Map对象的元素类型必须是AIDL服务支持的数据类型。不需要import

4)AIDL自动生成的接口。需要import

5)实现android.os.Parcelable接口的类。需要import

下面根据工程来解析:

进程间的通信分别为客户端和服务端新建一个eclipse工程,实现了从客户端向服务端发送请求。

源码结构图:

                  

1、传递的数据类类型定义

注意首先要传递的自定义类要implements Parcelable接口

Person类对象源码:

package com.aidl;

import android.os.Parcel;
import android.os.Parcelable;

public class Person implements Parcelable {
    // 自定义的类型具体包含的数据,本例为age和name。
    private intage = 0;
    private String name = null;

    // 这个构造函数,是方便我们在client中创新相关对象,并将之作为接口连接中调用方法的的参数
    public Person()
    {
    }

    /*提供构造函数,用于从Parcel中创建对象,也即是读的过程。这里设置为private,禁止外部调用 */
    private Person(Parcel in)
    {
        readFromParcel(in);
    }

    @Override
    publicint describeContents()
    {
        return 0;
    }

    /*
     * 【2】要实现Parcelable接口,需要实现writeToParcel()和readFromParcel(),实现将对象(数据)写入Parcel,
     * 和从Parcel中读出对象
     * 。需要注意,写的顺序和读的顺序必须一致,因为Parcel类是快速serialization和deserialization机制
     * ,和bundle不同,没有索引机制,是线性的数据存贮和读取。
     * 注意其中readFromParcel()并不是overrider,而是我们自己提供的方法,如果我们不提供,就要在 private
     * Person(Parcel in){ age = in.readInt(); name = in.readString(); }
     * 鉴于实际的数据类型会比小例子复杂,以及便于代码阅读,我们仿照writeToParcel()的命名,给出readFromParcel()
     */
    @Override
    public void writeToParcel(Parcel out, int flag)
    {
        out.writeInt(age); // 先写入age
        out.writeString(name); // 其次写如name
    }

    public void readFromParcel(Parcel in)
    {
        age = in.readInt(); // 先读出age,保持与写同顺序
        name = in.readString(); // 其次读出name,保持与写同顺序
    }

    /*
     * 实现Parcelable接口的类必须要有一个static
     * field称为CREATOR,用于实现Parcelable.Creator接口的对象
     * 。在AIDL文件自动生成的Java接口中,IBinder将调用Parcelable.Creator来获得传递对象:_arg1 =
     * cn.wei.flowingflying
     * .proandroidservice.Person.CREATOR.createFromParcel(data);
     */
    public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
        @Override
        public Person createFromParcel(Parcel source) {
            return new Person(source);
        }

        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }
    };

    /* 一系列getter,setter方法 */
    publicint getAge()
    {
        returnage;
    }

    public String getName()
    {
        returnname;
    }

    publicvoid setAge(intage)
    {
        this.age = age;
    }

    publicvoid setName(String name)
    {
        this.name = name;
    }
}

要在进程间传递非本地对象,要注意必须实现Parcelable接口。通过重写public void writeToParcel(Parcel out, int flag)来将对象的属性保存到传递出去的Parcel对象。此外还必须实现一个公共静态的Creator域:Parcelable.Creator<Person>
CREATOR,用于创建Person对象。

2、AIDL服务需要建立AIDL文件。在客户端和服务器端建立相同的aidl文件,并注意包名和文件名要完全一致。

自定义的类要注意在aidl文件中import.

IMyService.aidl源码:

package com.aidl;
import com.aidl.Person;
interface IMyService
{
    Map getPersonAll(in String tag, in Person person);
    Person getPerson();
}
类似于定义interface,可以再次提供相应的属性和方法。方法也可以接受零到多个参数。参数需要使用(in,out,inout)来修饰。

3、建立aidl文件后,Eclipse会自动生成com.aidl.IMyService.java文件:
/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: F:\\Android Workspace\\AIDLServer\\src\\com\\aidl\\IMyService.aidl
 */
package com.aidl;

public interface IMyService extends android.os.IInterface {
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements
            com.aidl.IMyService {
        private static final java.lang.String DESCRIPTOR = "com.aidl.IMyService";

        /** Construct the stub at attach it to the interface. */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.aidl.IMyService interface,
         * generating a proxy if needed.
         */
        public static com.aidl.IMyService asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.aidl.IMyService))) {
                return ((com.aidl.IMyService) iin);
            }
            return new com.aidl.IMyService.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        @Override
        public boolean onTransact(int code, android.os.Parcel data,
                android.os.Parcel reply, int flags)
                throws android.os.RemoteException {
            switch (code) {
            case INTERFACE_TRANSACTION: {
                reply.writeString(DESCRIPTOR);
                return true;
            }
            case TRANSACTION_getPersonAll: {
                data.enforceInterface(DESCRIPTOR);
                java.lang.String _arg0;
                _arg0 = data.readString();
                com.aidl.Person _arg1;
                if ((0 != data.readInt())) {
                    _arg1 = com.aidl.Person.CREATOR.createFromParcel(data);
                } else {
                    _arg1 = null;
                }
                java.util.Map _result = this.getPersonAll(_arg0, _arg1);
                reply.writeNoException();
                reply.writeMap(_result);
                return true;
            }
            case TRANSACTION_getPerson: {
                data.enforceInterface(DESCRIPTOR);
                com.aidl.Person _result = this.getPerson();
                reply.writeNoException();
                if ((_result != null)) {
                    reply.writeInt(1);
                    _result.writeToParcel(reply,
                            android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                } else {
                    reply.writeInt(0);
                }
                return true;
            }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.aidl.IMyService {
            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }

            @Override
            public android.os.IBinder asBinder() {
                return mRemote;
            }

            public java.lang.String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }

            @Override
            public java.util.Map getPersonAll(java.lang.String tag,
                    com.aidl.Person person) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.Map _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(tag);
                    if ((person != null)) {
                        _data.writeInt(1);
                        person.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_getPersonAll, _data,
                            _reply, 0);
                    _reply.readException();
                    java.lang.ClassLoader cl = (java.lang.ClassLoader) this
                            .getClass().getClassLoader();
                    _result = _reply.readHashMap(cl);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public com.aidl.Person getPerson()
                    throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                com.aidl.Person _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getPerson, _data, _reply,
                            0);
                    _reply.readException();
                    if ((0 != _reply.readInt())) {
                        _result = com.aidl.Person.CREATOR
                                .createFromParcel(_reply);
                    } else {
                        _result = null;
                    }
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        static final intTRANSACTION_getPersonAll = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final intTRANSACTION_getPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

    public java.util.Map getPersonAll(java.lang.String tag,
            com.aidl.Person person) throws android.os.RemoteException;

    public com.aidl.Person getPerson() throws android.os.RemoteException;
}

注意源码中实现了stub类:抽象类,继承了Binder

public static abstract class Stub extends android.os.Binder implements com.aidl.IMyService

4、接下来实现服务器端的service:

package com.aidl;

public class MyService extends Service{
    /*Service扩展Stub并实现要求的功能,相当于implements生成的IMyService.java*/
    public class MyServiceImpl extends IMyService.Stub
    {
        @Override
        public Map getPersonAll(String tag, Person person) throws RemoteException {
            Map<String, String> map = new HashMap<String, String>();
            map.put("tag", tag);
            map.put("name", person.getName());
            map.put("age", String.valueOf(person.getAge()));
            map.put("person", person.toString());
            return map;
        }

        @Override
        public Person getPerson() throws RemoteException {
            return new Person();
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new MyServiceImpl();
    }

}

在mainfest文件中注册service:

	<service
            android:name="com.aidl.MyService"
            android:process=":remote">
               <intent-filter>
             <!-- 指定客户端调用AIDL服务所需要的Action -->
             <actionandroid:name="com.aidl.action.IMyService"/>
             <categoryandroid:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </service>

5、在客户端的Activity中绑定使用Service

package com.example.aidlclient;

import com.aidl.IMyService;
import com.aidl.Person;

public class MainActivity extends Activity {
    private Button mybu;

    private final static String ACTION_TAG = "com.aidl.action.IMyService";
    //MyService可以当做普通的Service形式进行调用
    private IMyService iMyService;

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //获得service的实例
            iMyService = IMyService.Stub.asInterface(service);
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            iMyService = null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mybu = (Button) findViewById(R.id.mybu);
        //绑定Service
        bindService(new Intent(ACTION_TAG), serviceConnection, Context.BIND_AUTO_CREATE);

        mybu.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    doWithService();
                } catch (RemoteException e) {
                }
            }
        });
    }

    /*******操作Service提供的服务
     * @throws RemoteException ************/
    private void doWithService() throws RemoteException
    {
        Person person = iMyService.getPerson();
        person.setAge(10);
        person.setName("Mary");
        Log.i("doWithService", "getName      :" + person.getName());
        Log.i("doWithService", "getAge       :" + String.valueOf(person.getAge()));
        Log.i("doWithService", "getPersonAll :" + iMyService.getPersonAll("Map", person));
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        intid = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

使用bindService(new Intent(ACTION_TAG), serviceConnection,
Context.BIND_AUTO_CREATE);来对Service进行绑定。

在onServiceConnected中通过iMyService =
IMyService.Stub.asInterface(service);来获取实例;进而通过Service调用相关服务。

客户端在执行bindService的时候,成功绑定服务之后,会回调mConnection的onServiceConnected(),并且传回了服务端的通信接口IBinder,此IBinder即服务onBind()时返回的IBinder,详见mAIDLService.java。

在onServiceConnected(),客户端成功获取了服务端通信接口,实际上是本地代理对象,该对象存在于客户端进程空间,客户端只和代理对象交互,真正的IPC通信是本地代理对象和服务端的通信。

注意:bindService是异步实现的,绑定需要一定的时间,不可bindService之后立即执行iMyService的相关操作,因为可能为来得及绑定,导致iMyService仍为空。

整个交互流程如下:

1.客户端通过绑定服务,获取了服务的句柄(本地代理对象);

2.客户端执行onClick(),调用本地代理对象的get()等函数,本地代理对象调用mRemote.transact()发出远程调用请求;

3.服务端响应onTransact()执行this.get(),并将执行结果返回;

由于客户端只和本地代理对象即服务句柄通信,由代理对象进行真正的IPC操作,所以对客户端来说,IPC过程是透明的,调用远程操作如同调用本地操作一样。在客户端调用transact()时,会将服务描述DSCRIPTION写入到data里,在客户端onTransact时会验证,如果两个不一样,则不能通信。而DSCRIPTION是根据mInterface包名和接口名自动生成的,这就是为什么两个工程里的aidl文件要在同一个包的原因。

在这个过程中,aidl起到了桥梁的作用,规定统一了客户端和服务端的通信接口,使得客户端和服务端得以成功的通信。

具体的通信transact和onTransact的过程也就是利用Binder驱动通信的过程。

时间: 2024-10-03 14:03:18

Android--AIDL学习的相关文章

java/android 设计模式学习笔记(9)---代理模式

这篇博客我们来介绍一下代理模式(Proxy Pattern),代理模式也成为委托模式,是一个非常重要的设计模式,不少设计模式也都会有代理模式的影子.代理在我们日常生活中也很常见,比如上网时连接的代理服务器地址,更比如我们平时租房子,将找房子的过程代理给中介等等,都是代理模式在日常生活中的使用例子. 代理模式中的代理对象能够连接任何事物:一个网络连接,一个占用很多内存的大对象,一个文件,或者是一些复制起来代价很高甚至根本不可能复制的一些资源.总之,代理是一个由客户端调用去访问幕后真正服务的包装对象

AIDL学习

AIDL学习前知识 AIDL:Android Interface Definition Language,即Android接口定义语言 AIDL使用情景:Android中不同的进程之间不能直接通信,相互调用接口,实现数据的共享.此时,便能用AIDL来实现这中需求. Android使用Binder来实现进程间通信,Binder有点像一架桥梁,链接两个不同的进程: Binder能够携带processA的请求信息,告知processB需要调用processB的哪个接口,并返回processA所需要的接

疯狂Android讲义 - 学习笔记(八)

第10章 Service与BroadcastReceiver 10.1 Service简介 Service组件也是可执行的程序,有自己的生命周期,创建.配置Service与创建.配置Activity的过程基本相似.Service一直在后台运行,没有用户界面. 10.1.1 创建.配置Service 需要2个步骤:1 定义基础Service的子类,2 在AndroidManifest.xml文件中配置Service. Service与Activity都是从Context派生出来的,因此都可以调用C

(转载)你真的理解Android AIDL中的in,out,inout么?

前言 这其实是一个很小的知识点,大部分人在使用AIDL的过程中也基本没有因为这个出现过错误,正因为它小,所以在大部分的网上关于AIDL的文章中,它都被忽视了--或者并没有,但所占篇幅甚小,且基本上都是官方文档的译文,译者读者其实都不知其然.这几天在研究AIDL,偏偏我又是个执拗的性子,遇着不清不楚的东西就是想把它捋清楚,就下了些功夫研究了下AIDL中的定向tag,研究了下它的 in , out , inout . 整理而成此博文. 1.概述 首先要说的是定向tag是AIDL语法的一部分,而 in

java/android 设计模式学习笔记(14)---外观模式

这篇博客来介绍外观模式(Facade Pattern),外观模式也称为门面模式,它在开发过程中运用频率非常高,尤其是第三方 SDK 基本很大概率都会使用外观模式.通过一个外观类使得整个子系统只有一个统一的高层的接口,这样能够降低用户的使用成本,也对用户屏蔽了很多实现细节.当然,在我们的开发过程中,外观模式也是我们封装 API 的常用手段,例如网络模块.ImageLoader 模块等.其实我们在开发过程中可能已经使用过很多次外观模式,只是没有从理论层面去了解它. 转载请注明出处:http://bl

java/android 设计模式学习笔记(10)---建造者模式

这篇博客我们来介绍一下建造者模式(Builder Pattern),建造者模式又被称为生成器模式,是创造性模式之一,与工厂方法模式和抽象工厂模式不同,后两者的目的是为了实现多态性,而 Builder 模式的目的则是为了将对象的构建与展示分离.Builder 模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程.一个复杂的对象有大量的组成部分,比如汽车它有车轮.方向盘.发动机.以及各种各样的小零件,要将这些部件装配成一辆汽车,这个装配过

java/android 设计模式学习笔记(一)---单例模式

前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使用的时候也会有一些坑. PS:对技术感兴趣的同鞋加群544645972一起交流 设计模式总目录 java/android 设计模式学习笔记目录 特点 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 单例模式的使用很广泛,比如:线程池(threadpool).缓存(cache).对

Android NDK学习笔记(一) 为什么要用NDK?

NDK是什么 NDK是Native Development Kit的简称,即本地开发工具包.通过NDK,Android允许开发人员使用本地代码语言(例如C/C++)来完成应用的部分(甚至全部)功能.注意:由于翻译原因,有些地方也把Native翻译为"原生". NDK是SDK的一个补充,可以帮助你做这些事情: 生成可以在ARM CPU,Android 1.5(及以上)平台运行的JNI兼容的共享库. 将生成的共享库放置在应用程序项目路径的合适位置,使其能自动地添加进你最终的(和经过签名的)

Android:日常学习笔记(8)———探究UI开发(5)

Android:日常学习笔记(8)---探究UI开发(5) ListView控件的使用 ListView的简单用法 public class MainActivity extends AppCompatActivity { private String[] data={"Apple","Banana","Orange","Watermelon","Pear","Grape","

java/android 设计模式学习笔记(7)---装饰者模式

这篇将会介绍装饰者模式(Decorator Pattern),装饰者模式也称为包装模式(Wrapper Pattern),结构型模式之一,其使用一种对客户端透明的方式来动态的扩展对象的功能,同时它也是继承关系的一种替代方案之一,但比继承更加灵活.在现实生活中也可以看到很多装饰者模式的例子,或者可以大胆的说装饰者模式无处不在,就拿一件东西来说,可以给它披上无数层不一样的外壳,但是这件东西还是这件东西,外壳不过是用来扩展这个东西的功能而已,这就是装饰者模式,装饰者的这个角色也许各不相同但是被装饰的对