AIDL这项技术在我们的开发中一般来说并不是很常用,虽然自己也使用新浪微博的SSO登录,其原理就是使用AIDL,但是自己一直没有动手完整的写过AIDL的例子,所以就有了这篇简单的文章。
AIDL(AndRoid接口描述语言)是一种借口描述语言; 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的. 如果需要在一个Activity中, 访问另一个Service中的某个对象, 需要先将对象转化成 AIDL可识别的参数(可能是多个参数), 然后使用AIDL来传递这些参数, 在消息的接收端, 使用这些参数组装成自己需要的对象.
说白了,AIDL就是定义一个接口,客户端(调用端)通过bindService来与远程服务端简历一个连接,在该连接建立时会将返回一个IBinder对象,该对象是服务端Binder的BinderProxy,在建立连接时,客户端通过asInterface函数将该BinderProxy对象包装成本地的Proxy,并将远程服务端的BinderProxy对象赋值给Proxy类的mRemote字段,就是通过mRemote执行远程方法调用。需要对Binder机制有更深的理解,请转到老罗的系列文字吧,Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析。下面我们看一个AIDL实例。

AIDL接口声明
在src目录下创建一个com.example.advanceandroid.aidl包,然后在该包下创建一个ILogin.aidl文件,注意是创建文件而不是类或者接口类型。在ILogin.aidl中声明接口,实例如下 :

package com.example.advanceandroid.aidl;

interface ILogin {
String login();
}

注意看,接口和方法声明都不用public,方法加入public会提示错误。编写完后如果eclipse开启了自动编译则会在gen/com.example.advanceandroid.aidl下生成一个ILogin.java类,内容大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package com.example.advanceandroid.aidl;
public interface ILogin extends android.os.IInterface
{
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements
            com.example.advanceandroid.aidl.ILogin
    {
        private static final java.lang.String DESCRIPTOR = "com.example.advanceandroid.aidl.ILogin";
        /** Construct the stub at attach it to the interface. */
        public Stub()
        {
            this.attachInterface(this, DESCRIPTOR);
        }
        /**
         * Cast an IBinder object into an com.example.advanceandroid.aidl.ILogin
         * interface, generating a proxy if needed.
         */
        public static com.example.advanceandroid.aidl.ILogin asInterface(android.os.IBinder obj)
        {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.example.advanceandroid.aidl.ILogin))) {
                return ((com.example.advanceandroid.aidl.ILogin) iin);
            }
            return new com.example.advanceandroid.aidl.ILogin.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_login: {                            // 1、登录请求,执行的是this.login();
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _result = this.login();
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }
        private static class Proxy implements com.example.advanceandroid.aidl.ILogin
        {
            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.lang.String login() throws android.os.RemoteException                // 2、Proxy中的login,通过Binder机制实现IPC
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.lang.String _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_login, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }
        static final int TRANSACTION_login = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }
    public java.lang.String login() throws android.os.RemoteException;
}

可以看到,该类中自动生成了ILogin接口,该接口中又一个login()函数。但最重要的是里面生成了一个Stub类,该类集成子Binder类,并且实现了ILogin接口。Stub里面最重要的就是asInterface()这个函数,在这个函数中会判断obj参数的类型,如果是该obj是本地的接口类似,则认为不是IPC,会将该obj转换成ILogin类型;否则会通过自动生成的另一个内部类Proxy来包装obj,将其赋值给Proxy中的mRemote属性。Proxy类也实现了ILogin接口,在login()函数中,Proxy将通过Binder机制向服务端传递请求和数据,如上面代码中的注释2。这是客户端的工作算是完成了。

服务端AIDL接口
服务端也需要在相同的包下创建同名的aidl文件,我们直接将客户端的com.example.advanceandroid.aidl包下的ILogin.aidl拷贝到服务端即可,如果用到了自定义的类型,那么该自定义类型也需要在客户端、服务端都有。拷贝完aidl后,在服务端程序中也会在gen中生成对应的ILogin.java文件,内容同客户端一样。这里的重点我们要看onTransact函数,即上述代码中的注释1处,可以看到,在case TRANSACTION_login处执行了this.login()函数,意思是当接收到客户端的TRANSACTION_login请求时,执行this.login()函数,通过客户端的分析我们知道,当我们调用login()时实际上就是通过mRemote向服务端提交了一个TRANSACTION_login请求,因此就两端通过Binder机制就对接上了,我们可以简单的理解为C/S模式。

服务端还没有完,最重要的一步时建立一个Service,内容大致如下 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* AIDL服务端接口,LoginStubImpl实现了ILogin接口.
*
* @author mrsimple
*/
public class LoginService extends Service {
    /**
     *
     */
    IBinder mBinder = new LoginStubImpl();
    /**
     * @author mrsimple
     */
    class LoginStubImpl extends Stub {
        @Override
        public String login() throws RemoteException {
            return "这是从 " + this.getClass().getName() + " 返回的字符串";
        }
    }
    /*
     * 返回Binder实例,即实现了ILogin接口的Stub的子类,这里为LoginStubImpl
     * [url=home.php?mod=space&uid=133757]@see[/url] android.app.Service#onBind(android.content.Intent)
     */
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}

该Service我们这里命名为LoginService,继承自Service,然后建一个名为LoginServiceImpl的内部类,该类继承自自动生成的Stub,然后实现login()方法。在LoginService中声明一个IBinder字段mBinder :

IBinder mBinder = new LoginStubImpl();

并且在LoginService的onBind函数中将mBinder对象返回。即在客户端建立与服务端的连接时,会调用onBind方法将mBinder对象返回,在客户端的ServiceConnection类的onServiceConnected函数中得到的对象IBinder就是经过BinderProxy包装的LoginService中的mBinder对象。因此在服务端中的onTransact中调用的this.login()函数实际上就是调用的LoginStubImpl中的login()函数。

在服务端程序的AndroidManifest.xml中注册LoginService,如下 :

1
2
3
4
5
6
<!-- aidl server service -->
    <service android:name="com.example.advanceandroid.aidl.LoginService">
        <intent-filter>
             
        </action></intent-filter>
    </service>

客户端建立连接

在Activity中加入如下代码 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
ServiceConnection mLoginConnection = new ServiceConnection() {
       @Override
       public void onServiceDisconnected(ComponentName name) {
           Log.d("", "### aidl disconnected.");
       }
       @Override
       public void onServiceConnected(ComponentName name, IBinder service) {
           Log.d("", "### aidl onServiceConnected.     service : "+ service.getClass().getName());
           ILogin login = Stub.asInterface(service);
           Log.d("", "### after asInterface : " + login.getClass().getName());
           try {
               Log.d("", "### login : " + login.login());
               // Toast.makeText(MainActivity.this, "onServiceConnected : " +
               // login.login(),
               // Toast.LENGTH_SHORT).show();
           } catch (RemoteException e) {
               e.printStackTrace();
           }
       }
   };
   @Override
   protected void onResume() {
       super.onResume();
       // 服务端的action
       Intent aidlIntent = new Intent("com.example.advanceandroid.aidl.LoginService");
       bindService(aidlIntent, mLoginConnection, Context.BIND_AUTO_CREATE);
   }
   @Override
   protected void onStop() {
       super.onStop();
       // unbind
       unbindService(mLoginConnection);
   }

运行

先运行服务端程序,然后在启动客户端程序,可以看到客户端输出如下Log:

1
2
3
09-02 10:40:54.662: D/(9589): ### aidl onServiceConnected.     service : android.os.BinderProxy
09-02 10:40:54.662: D/(9589): ### after asInterface : com.example.advanceandroid.aidl.ILogin$Stub$Proxy
09-02 10:40:54.662: D/(9589): ### login : 这是从 com.example.advanceandroid.aidl.LoginService$LoginStubImpl 返回的字符串

可以看淡onServiceConnected(ComponentName name, IBinder service)中的service对象是BinderProxy类型,经过asInterface转换后被包装成了Proxy类型,但是调用的时候,执行的是服务端LoginStubImpl中的login()函数。因此,LoginStubImpl实例mBinder被服务端包装成BinderProxy类型,再经过客户端的Proxy进行包装,通过Binder机制进行数据传输,实现IPC。

本文转自 一点点征服   博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/7306173.html,如需转载请自行联系原作者

Android AIDL实例解析相关推荐

  1. Android开发之IPC进程间通信-AIDL介绍及实例解析

    一.IPC进程间通信 IPC是进程间通信方法的统称,Linux IPC包括以下方法,Android的进程间通信主要采用是哪些方法呢? 1. 管道(Pipe)及有名管道(named pipe):管道可用 ...

  2. 转 android anr 分析示例,[摘]Android ANR日志分析指南之实例解析

    前文<[摘]Android ANR日志分析指南>也摘抄了如何分析,接下来通过实例解析. 一.主线程被其他线程lock,导致死锁 waiting on <0x1cd570> (a ...

  3. delphi android 蓝牙,Android实例-Delphi开发蓝牙官方实例解析(XE10+小米2+小米5)

    [实例简介] 2.保证无毒 3.简单,方便,实用 4.实例可以自行改用 5.如有非法,本人无法律责任,由改动代码人负责! 6.需要更多本人作品,查找标签"朱建强" 7.请下载,杀毒 ...

  4. Android NFC开发详解 总结和NFC读卡实例解析

    文章目录 前言 一.什么是NFC? 二.基础知识 1.什么是NDEF? 2.NFC技术的操作模式 3.标签的技术类型 4.实现方式的分类 5.流程 三.获取标签内容 1.检查环境 2.获取NFC标签 ...

  5. 开发android 输入法,Android输入法开发实例解析 Android开发技术

    Android输入法开发实例解析 Android开发技术 2013 年 4 月 13 日 这里我们建立表1为BiHua,同时构建两个字段,字段1为"input"来存放输入的,字段2 ...

  6. Android Aidl (一)通过实例初探Aidl

    在Android的应用开发过程中,遇到与Service进行通信时,会使用Aidl.那到底Aidl是什么?Aidl的优势是什么?实现的原理是怎么样的? 习惯从例子入手,从实际应用加深对知识点的了解.我们 ...

  7. Android 水果机游戏实例解析

     [Cocos2d-x相关教程来源于红孩儿的游戏编程之路 CSDN博客地址:http://blog.csdn.net/honghaier]          Android 水果机游戏实例解析 近段时 ...

  8. Android中JSON解析细解及实例

    1.JSON解析 (1).解析Object之一: {"url":"www.cnasda.com"} 解析方法: JSONObject demoJson = ne ...

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

    前言 这其实是一个很小的知识点,大部分人在使用AIDL的过程中也基本没有因为这个出现过错误,正因为它小,所以在大部分的网上关于AIDL的文章中,它都被忽视了--或者并没有,但所占篇幅甚小,且基本上都是 ...

最新文章

  1. mycheckpoint
  2. C语言多线程教程(pthread)(线程创建pthread_t,指定线程run方法pthread_create,加mutex锁,解锁,伪共享 false sharing【假共享】)
  3. 分布式系统开发注意事项
  4. servlet返回数据给html_Servlet 简介
  5. 话里话外: 信息化与高层参与度的关系
  6. c语言课设报告时钟vc环境,C语言课程设计报告模拟时钟转动程序
  7. 炫酷科技感超前的电子产品发布广告海报psd分层模板,带给你炫酷的未来感
  8. 使用nosetests对webpy程序做单元测试
  9. hdu,2050,折线分割平面
  10. php多图片打包下载
  11. 【商品架构day8】京东几百亿的商品怎么搜索
  12. html5音乐播放器格式midi,HTML5 Audio时代的MIDI音乐文件播放
  13. MySQL查询数据详细
  14. php中划弧线,cad画弧形的快捷键是什么?如何画弧形?
  15. php的seeder是什么,Laravel框架使用Seeder实现自动填充数据功能
  16. ch341a i2c 安卓_CH341A实现USB转I2C的问题
  17. Linux学习(六):proftpd搭建,完美解决vsftpd中文引号bug
  18. elasticsearch 生产级别深度优化
  19. java 历遍 类_[Java] 遍历指定包名下所有的类(支持jar) | 学步园
  20. Ubuntu18.04安装显卡驱动+CUDA

热门文章

  1. Kubernetes 常见运维技巧总结
  2. Linux篇:通配符的应用
  3. 25 个必须记住的SSH 命令
  4. 如何对应紧急依赖过来的作业,要有自己的原则
  5. Jetty使用内存过大的解决方案
  6. SQL Server抛出异常信息 RAISERROR
  7. log4j不输出日志的解决方案
  8. Android Studio支持Java1.8的解决方案
  9. 解决CentOS6.4 Docker “Couldn‘t connect to Docker daemon ...“ 问题
  10. 解决ActiveX Control异常:“没有注册类(异常来自 HRESULT:0x80040154(REGDB_E_CLASSNOTREG))“