Android跨进程通信——AIDL使用方法浅析

同时记录在我的独立博客:http://www.liushenming.com/?p=241

此篇博客将介绍Android应用开发中的一种常用的跨进程通信手段——AIDL的使用。

我花了一周时间,查阅了许多的资料,在众多AIDL介绍的文章中来来回回,反反复复地梳理线索,将一些概念反复推敲,最终得出了AIDL使用的初步教程。之所以说是AIDL使用方法的初步教程,是因为IPC实在是一个很有学问的技术,我学识有限,在看罗升阳老师有关AIDL的一系列博客后,我认为,我最多只能做一个使用方法的介绍,而不是一个原理分析,因为"reading the fucking source code"的能力还差得很远。
在这一周之前,我对AIDL是完全没有一点认识的,最初使用过一次,也是照着别人的教程一步步做,完全不知道它到底是什么情况。但是经过了这一周的学习之后,我觉得我在AIDL的使用上已经没有问题了,如果你也是刚好想要学习AIDL的使用,那么我的博客也许能给你带来一些帮助。


首先,我们要弄清楚一下一系列问题:
1.什么是AIDL?
2.什么时候我需要使用AIDL?
3.怎么使用AIDL?
4.它自动生成的同名java文件是啥情况?
5.里面两个内嵌类Stub,Proxy是什么关系?
6.它和Service怎么扯上的?
7.Binder,IBinder是什么玩意?IPC??
8.Parcel,老看见你,是什么东西啊,来干嘛的?
9.还有BinderProxy?
10.Binder驱动哪来的,运行于内核空间?
12.ServiceManager也是个Server,C/S架构?
13.好多C++代码上上下下啊,好烦啊。
14.什么内存映射来映射去的,很疲惫啊。
......


<!--more-->


好吧,我就是在上面的问题中挣扎过了这一周,最后终于明白AIDL的好了,因为它是一种开发手段,让我们开发者能够无意识地,轻松地使用跨进程通信,而无需写大量地重复代码,因为它们都被封装得很简单。


进入正题,什么是AIDL?
<blockquote>百度百科:
" Android Interface Definition Language,即Android接口定义语言。
Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信。为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现。与很多其他的基于RPC的解决方案一样,Android使用一种接口定义语言(Interface Definition Language,IDL)来公开服务的接口。我们知道4个Android应用程序组件中的3个(Activity、BroadcastReceiver和ContentProvider)都可以进行跨进程访问,另外一个Android应用程序组件Service同样可以。因此,可以将这种可以跨进程访问的服务称为AIDL(Android Interface Definition Language)服务。"</blockquote>
这段话我在研究AIDL时看了几遍,没看懂。但是现在再一看,就是这样。
Android接口定义语言。也就是说AIDL就是.aidl文件就是用来定义接口的,之所以使用它呢,是为了给Service提供被跨进程访问的能力,换句话说就是让能够让Service提供跨进程服务。问题来了,什么时候Service是跨进程的,什么时候它不是跨进程的?这个问题很关键,可以说是必须要清楚的一个问题。
举个例子,当我们在一个应用里,写了两个Activity:Activity1.java、Activity2.java,写了一个Service:Service1.java。我在Activity1的Context中使用startActivity(Intent)起了Activity2,这是不是跨进程了?答案是可能是,也可能不是。当我们在应用的AndroidManifest.XML文件中为activity或Service指定了android:process="..."属性以后,我们就可以让对应的Activity和Service运行在指定的进程中。如果我们不指定android:process属性,那么它们都运行在默认以应用包名为进程名的对应进程中。关于这个android:process属性的介绍,可以查到很多资料,这里不细说了,就是要有这个意识,不一定同一个应用中的组件都运行在同一个process里。
OK,那不同应用的组件之间一定运行在不同进程中吗?一般情况下是这样的,但我也不能说的太绝对,因为有些特殊情况下不同应用的组件会运行在同一个进程中,这是后话,一般可以默认不同应用是运行在不同进程中的。
清楚了这一点后,我们抛出下一个梗,我想在运行于process A的Activity中调用运行于process B的Service的一些对象方法,怎么搞?OK,有个办法是广播。你们互相发广播吧,这是可以的,我们需要定义一系列的广播。举个具体点的例子吧,否则说起来真不方便:假设有一个Service叫做“天气助手”,里面有一个类叫WeatherAnswer。这个WeatherAnswer中定义了一系列的方法,比如getDay(),getTemp(),getCity(),getTemp(Int).......那么一大串的方法下来,我们使用广播显然有点儿吃力啊,我们要在Service的广播接收器中为每个方法定义一个广播项,然后还要判断解析出传入的参数来,这显然是个不科学的用法。广播更多的时候是被用来处理一些消息,而传递数据这件事不该过于依赖广播。那该怎么办呢?什么ContentProvider之流的跨进程手段更是不济,此时AIDL就呼之欲出了。
在这呼之而出之前有个问题需要在此时抛出来:如果该Service和我们的Activity是在同一个进程里的话,同样的需求该如何实现?这个问题同样可以由AIDL来解决,并且对于应用开发者来说,开发的步骤是一模一样的,也就是说AIDL对上层开发和底层机制的隔离做得非常人性化。
终于进入正题了,我们先来约定一下。我们的Service叫做WeatherService,它在后台跑着(先不管它是不是和Activity运行在同一个进程里),其中有一个叫做MyAIDLImpl的对象,专门提供天气预报应有的各种服务,它被当做跨进程通信的Server,顾名思义,它是提供服务的对象,所以是Server。然后我们要在一个MainActivity中使用MyAIDLImpl对象提供给我们的方法int getWeather(),float getTemp(int day),String getCity(),就先这三个方法吧,由于Activity里需要使用Server提供的服务,所以它是Client。
我们先来定义一下Server的接口,创建一个MyWeatherAIDL.aidl文件。在里面定义int getWeather(),float getTemp(int day),String getCity()三个接口,(我使用的eclipse,androidstudio也是类似的过程)在包里手动创建一个MyWeatherAIDL.aidl文件,然后用像写一个接口一样的语法定义方法:


<code lang="java">
package com.example.hello;


interface MyWeatherAIDL{
    int getWeather();
    float getTemp(int day);
    String getCity();
}
</code>
这样保存之后,eclipse为我们自动生成了对应的java文件(aidl也就是为了方便的告诉环境,我们要什么样的接口,然后接下来环境说,哦,是AIDL啊,那我自动帮你生成个java文件吧,这才是你真正要的,你自己写的话太累了,just这个目的)。生成的java文件位于/gen/com/example/hello下,打开来看看eclipse都为我们做了些什么:


<code lang="java">
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: E:\\eclipse_workspace\\Hello\\src\\com\\example\\hello\


\MyWeatherAIDL.aidl
*/
package com.example.hello;


public interface MyWeatherAIDL extends android.os.IInterface
{
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements
        com.example.hello.MyWeatherAIDL{


        private static final java.lang.StringDESCRIPTOR = "com.example.hello.MyWeatherAIDL";


        /** Construct the stub at attach it to the interface. */
        public Stub(){
            this.attachInterface(this, DESCRIPTOR);
        }
        /**
        * Cast an IBinder object into an com.example.hello.MyWeatherAIDL interface,
        * generating a proxy if needed.
        */


        public static com.example.hello.MyWeatherAIDL asInterface
            (android.os.IBinder obj){
            if ((obj==null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin!=null)&amp;&amp;(iin instanceof 
                com.example.hello.MyWeatherAIDL))){
                return ((com.example.hello.MyWeatherAIDL)iin);
            }
            return new com.example.hello.MyWeatherAIDL.Stub.Proxy(obj);
        }


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


        @Override public boolean onTransact(int code, android.os.Parcel data, 
            android
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值