标签:
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组件,serviceManager和binder驱动。client组件和server组件进行通信,要通过ServiceManager查询server组件的引用。server向ServiceManager注册一个binder尸体,client通过ServiceManager获得binder实体的一个引用,这样client和server就可以通信了
在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的方式有点不一样。
下面是一个简单的例子
在项目名称上右键>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 statements interface 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<Girl> CREATOR=new Creator<Girl>() { @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]; } }; }
如图
接着写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"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.test.huangxingli.aidlserver" > <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <service android:name="com.test.huangxingli.aidlserver.MAIDLServerService" android:process=":remote" > <intent-filter> <action android:name="com.test.huangxingli.aidlserver.MAIDLServerService"></action> </intent-filter> </service> </application> </manifest>
server端结构如图
首先要拷贝AIDL文件,这里要保证文件的内容一模一样,包括包的名称,比如本例子中服务器端AIDL文件所在包的名称是com.test.huangxingli.aidlserver,如何做到这一点,先新建一个项目,然后在:项目文件夹/app/src/main目录下建立一个aidl文件夹,与java文件夹同级,在Android Studio中就可以看到这个目录,在这个目录上右键New>Package,建立一个com.test.huangxingli.aidlserver的包,再将aidl文件拷进去。这样才能保证生成的java接口文件完全一样,否则会提示找不到接口。参照下图操作
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);
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> 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; } }; }
代码先安装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
Android studio 中创建AIDL Service
标签:
原文地址:http://blog.csdn.net/kpioneer123/article/details/51219188