过去Android开发工具主要是Eclipse,那时使用AIDL记得挺简单的,这几天找工作复习AIDL,发现在Android Studio上按照书上的做法根本跑不通,又在网上找办法,全他妈的抄来抄去,虽然有图有文看上去一目了然,实际根本跑不通,有些配置根本就没讲,要知道程序开发这玩意儿差一点也不行啊!搞了两个小时,总算知道Android Studio下怎么用AIDL了。将今天下午的经验总结如下。
本教程以两个app---ShenZhen(服务端)和ChengDu(客户端)为例,效果为点击ChengDu中的一个按钮后,从ShenZhen获取到一个String,显示在按钮上。
1、先做服务端部分。右键工程的src,如下图 1-a,创建一个.aidl文件IShenZhenAidlInterface.aidl。新建完成后,AS会自动创建一个与java目录同级的目录来存放该aidl文件,结果如下图1-b。

图1-a 创建aidl文件

图1-b 创建第一个aidl文件后src下的目录情况
2、编辑该aidl文件,添加一些方法,可供客户端调用。如下图2-a。

图2-a 向aidl文件中添加供客户端调用的方法
3、编译,如图3-a。编译结束后如图3-b。

图3-a,编译aidl文件,生成响应的.java文件。

图3-b 编译后,可看到在上图所标示的地方生成了相应的.java文件
4、创建供客户端调用的Service。如图4-a。

图4-a 供客户端调用的Service

图4-b 配置Service。
至此 ,服务端准备完毕。在手机上运行一下,发现没有问题。
开始客户端部分。
1、复制服务端ShenZhen的aidl目录到客户端ChengDu的main目录下,即直接在Android Studio中右键服务端的aidl目录,复制,然后右键客户端的main目录,粘贴。结果如下图1-a。

图1-a 客户端被粘贴aidl目录后
2、同样。build--make PRoject,在客户端生成.java文件。
3、用bind方式启动Service。代码如下。
package chengdu.sichuan.com.chengdu;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.IBinder;import android.os.RemoteException;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.Toast;import shenzhen.guangdong.com.shenzhen.IShenZhenAidlInterface;public class ChengDuActivity extends AppCompatActivity { Button button; IShenZhenAidlInterface shenZhenAidlInterface; ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { shenZhenAidlInterface=IShenZhenAidlInterface.Stub.asInterface(service); try { button.setText(shenZhenAidlInterface.getName()); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.cheng_du); button= (Button) findViewById(R.id.bind); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //之所以用Action来启动Service,是因为发现用带有ComponentName的intent启动不了。 //原因尚未搞清楚。 bindService(new Intent("shenzhen"),serviceConnection, Context.BIND_AUTO_CREATE); } }); }}至此,相信很多人都已经成功了,但难处不在这里。这里传递的只是一个String,如果涉及到自定义的类,该如何用呢?下面才是重点。
AIDL可支持的数据类型出了基本数据类型,只有List、Map、Parcelable和本身就是AIDL格式的接口。以网上流行的类Book来讲解,如果我们启动Service后,客户端想获取到一个从服务端传过来的Book对象该怎么办呢?很显然,需要Book去实现Parcelable接口。
首先,
1、在服务端ShenZhen创建一个Book.aidl,如下所示(请一定注意所在目录,为方便,请尽量让所有aidl相关文件在同一目录下)

其中,它的默认代码实现是这样的
// Book.aidlpackage shenzhen.guangdong.com.shenzhen;// Declare any non-default types here with import statementsinterface Book { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString);}我们将其修改成这样// Book.aidlpackage shenzhen.guangdong.com.shenzhen;parcelable Book;2、创建一个同名类Book,实现Parcelable接口。
package shenzhen.guangdong.com.shenzhen;import android.os.Parcel;import android.os.Parcelable;/** * Created by Bamboo on 2017/2/27. */public class Book implements Parcelable { public String bookName; public Book(String name) { bookName=name; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(bookName); } public static Creator<Book> CREATOR = new Creator<Book>() { @Override public Book createFromParcel(Parcel source) { return new Book(source.readString()); } @Override public Book[] newArray(int size) { return new Book[0]; } };}3、我们为IShenZhenAidlInterface.aidl添加一个方法getBook( ),用以向客户端返回一个Book。// IShenZhenAidlInterface.aidlpackage shenzhen.guangdong.com.shenzhen;import shenzhen.guangdong.com.shenzhen.Book; //注意!这一句的引入很重要// Declare any non-default types here with import statementsinterface IShenZhenAidlInterface { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); String getName( ); Book getBook( );}4、由于接口的改变,我们的Service中Stub也要添加getBook( )方法的实现。package shenzhen.guangdong.com.shenzhen;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import shenzhen.guangdong.com.shenzhen.Book;public class ShenZhenService extends Service { IShenZhenAidlInterface.Stub iBinder = new IShenZhenAidlInterface.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public String getName() throws RemoteException { return "我的电脑"; } @Override public shenzhen.guangdong.com.shenzhen.Book getBook() throws RemoteException { return new Book("西游记"); } }; public ShenZhenService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. return iBinder; }}好了,我们试着build一下,看会怎样。结果,如下图。这也是很多教程中都没有提到的地方--找不到Book!
这就需要配置app的gradle
apply plugin: 'com.android.application'android { compileSdkVersion 25 buildToolsVersion "25.0.1" defaultConfig { applicationId "shenzhen.guangdong.com.shenzhen" minSdkVersion 14 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets { main{ java.srcDirs = ['src/main/java', 'src/main/aidl'] } }}dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.1.1' testCompile 'junit:junit:4.12'}再运行一下,OK!客户端做类似修改。成功运行。传递对象的关键就在于上面gradle里的红色配置以及即使在相同包下也要import,这是AIDL的特殊之处。
新闻热点
疑难解答