1、概述

 AIDL在android系统中的作用

AIDL,Android Interface definition language的缩写,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口。最近看了下AIDL在Android系统中的用法,在网上看到很多初学的朋友不太明白AIDL的实际作用,android提供了很多进程间通信的组件,像action、broadcast、contentprovide都可以实现进程间的通信,为什么还要用AIDL这个东西呢?我在android源码中实现了一个自己写的AIDL例子,用以简单解释下AIDL的作用。

有开发过蓝牙或者WIFI应用的朋友肯定都知道,要去操作它必须先获得一个管理类,比如WIFI的管理类是WifiManager,通过getSystemService(Context.WIFI_SERVICE)就可以得到wifi的管理权限,这个提供了很多的方法可以让用户去操作它,比如打开wifi可以调用setWifiEnabled(true)方法。那这个Manager到底做了什么工作呢?是怎样实现打开wifi的呢?其实这个Manager只是一个管理类,真正干活的另有其人,是一个叫WifiService的系统服务。在Android系统中有很多的Manager,wifi的管理类叫WifiManager,蓝牙的管理类叫BluetoothManager,但是,只要有xxxManager.java,就会有Ixxx.aidl,并且有xxxService.java。这个aidl类就是实现Manager和Service通信的桥梁。


Binder驱动,Binder客户端、服务端这三者之间的关系:

binder通信的四个角色应该是client组件,server组件,serviceManagerbinder驱动。client组件和server组件进行通信,要通过ServiceManager查询server组件的引用。serverServiceManager注册一个binder尸体,client通过ServiceManager获得binder实体的一个引用,这样clientserver就可以通信了

2、Android studio 中AIDL的使用


在eclipse里面操作时aidl文件个java文件都放在一个包下, 客户端直接将该包复制到自己的目录下,然后可以另外建另外一个包放其他代码。但在android studio下面这样是不可以的,需要在src单独建一个AIDL文件夹,将aidl文件放在里面,java文件在另外的包下,这样就导致服务端项目与客户端项目的包名必须相同。在as中project相当于es的workspace,moudle相当于es的project,在eclipse里面是两个project在通信,so 我猜测在as中是两个mould在通信,因此建了一个project(里面自带一个app module),让app moulde作为客户端然后又另外加了一个服务端moudle 叫aidlserver。在aidlserver的project视图下面的src下面右键new 选择AIDL ,AIDL Folder ,然后将自己的aidl文件放入其中。


在Android Studio下创建AIDL Serivce。

        建立ADIL Service的步骤比建立普通Service要多一些,主要有:

        1、创建AIDL文件,在这里面定义远程接口。

        2、生成Java接口文件。

        3、建立一个Service的子类,并且记得在AndroidManifest.xml文件中配置。

       在客户端调用ADIL Servie:

        1、拷贝服务器端的AIDL文件,并生成Java接口文件。

        2、用BindService来调用Service,与调用普通Serivce相类似,只是获取IBinder的方式有点不一样。


下面是一个简单的例子

一、建立服务端AIDL文件

        在项目名称上右键>NEW>AIDL>AIDL File,这样就创建了一个ADIL文件,命名为AIDLServerService.aidl

          

package com.test.huangxingli.aidlserver;import com.test.huangxingli.aidlserver.Girl;// Declare any non-default types here with import statementsinterface AIDLServerService {            String sayHello();            Girl getGirl();}
再创建 Girl.aidl
package com.test.huangxingli.aidlserver;parcelable Girl;

建好这两个文件后再编写Girl.java .注意要先写Girl.aidl然后再写Girl.java 刚开始时 我先写的Girl.java 然后再写Girl.aidl时提示不能创建重名的文件。

Girl.java如下:

package com.test.huangxingli.aidlserver;import android.os.Parcel;import android.os.Parcelable;/** * Created by huangxingli on 2015/3/27. */public class Girl  implements Parcelable{    String name;    int age;    public Girl() {    }    public String getName() {        return name;    }    public int getAge() {        return age;    }    public void setName(String name) {        this.name = name;    }    public void setAge(int age) {        this.age = age;    }    @Override    public int describeContents() {        return 0;    }    @Override    public void writeToParcel(Parcel dest, int flags) {        dest.writeString(name);        dest.writeInt(age);    }    public static final Creator CREATOR=new Creator() {        @Override        public Girl createFromParcel(Parcel source) {            Girl girl=new Girl();            girl.setName(source.readString());            girl.setAge(source.readInt());            return girl;        }        @Override        public Girl[] newArray(int size) {            return new Girl[size];        }    };}



然后菜单中选择Build>Rebulid Project,这样就生成了java接口文件,地址在项目文件夹/app/build/generated/aidl里面

如图

 

接着写Service类MAIDLServerService,如下:

package com.test.huangxingli.aidlserver;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;public class MAIDLServerService extends Service {    public MAIDLServerService() {    }    AIDLServerService.Stub binder=new AIDLServerService.Stub() {        @Override        public String sayHello() throws RemoteException {            return "hello, i am from AIDLServerService";        }        @Override        public Girl getGirl() throws RemoteException {            Girl girl=new Girl();            girl.setAge(25);            girl.setName("lily");            return girl;        }    };    @Override    public IBinder onBind(Intent intent) {        // TODO: Return the communication channel to the service.       return binder;    }}
然后在AndroidManifest.xml中里面将该服务器端的Service注册一下:如下
<?xml version="1.0" encoding="utf-8"?>                                                                


server端结构如图


二、建立客户端AIDL文件

首先要拷贝AIDL文件,这里要保证文件的内容一模一样,包括包的名称,比如本例子中服务器端AIDL文件所在包的名称是com.test.huangxingli.aidlserver,如何做到这一点,先新建一个项目,然后在:项目文件夹/app/src/main目录下建立一个aidl文件夹,与java文件夹同级,在Android Studio中就可以看到这个目录,在这个目录上右键New>Package,建立一个com.test.huangxingli.aidlserver的包,再将aidl文件拷进去。这样才能保证生成的java接口文件完全一样,否则会提示找不到接口。参照下图操作



核心部分: 在网上很多aidl程序客户端无法绑定Service,因为Android5.0以后,也就是说从Lollipop开始,service服务必须采用显示方式启动,否则会报错Service Intent must be explitict 如何解决Android 5.0中出现的警告:Service Intent must be expli 该链接中, 第一种在添加setpackage这句代码后提示AIDL的service的绑定失败,第二种方式解决了改问题,我也是用第二种方法解决
 结合我们的项目该怎么写了,如下:
  Intent mIntent = new Intent();                mIntent.setAction("com.test.huangxingli.aidlserver.MAIDLServerService");                Intent eintent = new Intent(createExplicitFromImplicitIntent(MainActivity.this, mIntent));                bindService(eintent,connection,BIND_AUTO_CREATE);                MainActivity.this.startService(eintent);

请注意,bindService 应在 startService之前
下面是我的客户端MainActivity.java的代码:
package com.test.huangxingli.aidlserver;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.content.pm.PackageManager;import android.content.pm.ResolveInfo;import android.os.IBinder;import android.os.RemoteException;import android.support.v7.app.ActionBarActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.TextView;import java.util.List;public class MainActivity extends ActionBarActivity {    TextView textView;    Button button;    AIDLServerService aidlServerService;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        button= (Button) findViewById(R.id.button);        textView= (TextView) findViewById(R.id.textView);        button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {//                Intent intent=new Intent();//                intent.setAction("com.test.huangxingli.aidlserver.MAIDLServerService");//你定义的service的action//                intent.setPackage(getPackageName());////                bindService(intent,connection,BIND_AUTO_CREATE);                Intent mIntent = new Intent();                mIntent.setAction("com.test.huangxingli.aidlserver.MAIDLServerService");                Intent eintent = new Intent(createExplicitFromImplicitIntent(MainActivity.this, mIntent));                bindService(eintent,connection,BIND_AUTO_CREATE);                MainActivity.this.startService(eintent);            }        });    }    /***     * Android L (lollipop, API 21) introduced a new problem when trying to invoke implicit intent,     * "java.lang.IllegalArgumentException: Service Intent must be explicit"     *     * If you are using an implicit intent, and know only 1 target would answer this intent,     * This method will help you turn the implicit intent into the explicit form.     *     * Inspired from SO answer: http://stackoverflow.com/a/26318757/1446466     * @param context     * @param implicitIntent - The original implicit intent     * @return Explicit Intent created from the implicit original intent     */    public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {        // Retrieve all services that can match the given intent        PackageManager pm = context.getPackageManager();        List resolveInfo = pm.queryIntentServices(implicitIntent, 0);        // Make sure only one match was found        if (resolveInfo == null || resolveInfo.size() != 1) {            return null;        }        // Get component info and create ComponentName        ResolveInfo serviceInfo = resolveInfo.get(0);        String packageName = serviceInfo.serviceInfo.packageName;        String className = serviceInfo.serviceInfo.name;        ComponentName component = new ComponentName(packageName, className);        // Create a new intent. Use the old one for extras and such reuse        Intent explicitIntent = new Intent(implicitIntent);        // Set the component to be explicit        explicitIntent.setComponent(component);        return explicitIntent;    }    ServiceConnection connection=new ServiceConnection() {        String content;        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            aidlServerService=AIDLServerService.Stub.asInterface(service);            try {                content=aidlServerService.sayHello()+"\n";                Girl girl=aidlServerService.getGirl();                content +="my name is "+girl.getName();                textView.setText(content);            } catch (RemoteException e) {                e.printStackTrace();            }        }        @Override        public void onServiceDisconnected(ComponentName name) {            aidlServerService=null;        }    };}

好了,就到这里就可以运行程序了 结果如下
可以看到,点击BindService之后,服务端执行了onCreate和onBind的方法,并且客户端执行了onServiceConnected方法,调用原本在Server端才有的方法语句,标明服务器与客户端已经联通。

资源下载

代码先安装server端的代码,然后再安装client端的。。。



参考文献:

http://blog.csdn.net/huangxingli/article/details/44674751

http://blog.csdn.net/lmj623565791/article/details/38461079

http://blog.csdn.net/shenzhonglaoxu/article/details/42737195

http://www.2cto.com/kf/201501/370478.html

更多相关文章

  1. Android文件路径
  2. android读写文件函数代码
  3. 基于Android扫描sd卡与系统文件的介绍
  4. Android窗口抖动之动画实现
  5. 详解Android中实现热更新的原理
  6. android mediarecord 实现暂停断点录音功能
  7. Android仿人人客户端(v5.7.1)——网络模块处理的架构
  8. android java 文件 设置 对应 layout 下 布局文件.xml
  9. NPM 和webpack 的基础使用

随机推荐

  1. Android(安卓)圆角&圆形图片
  2. 【Android(安卓)Audio】Audio: summery o
  3. Android(安卓)菜单 使用XML
  4. 手机客户端版csdn搜索
  5. Android(安卓)check if app debug or rel
  6. Android(安卓)开发笔记第二季 DialogFrag
  7. recyclerview最简单的滑动删除
  8. [置顶] android 系统图片剪裁
  9. Android(安卓)手机号码格式验证
  10. Android(安卓)百度 Map----定位功能