aidl是Android中用于跨进程通讯的语言。当需要在项目中使用多个进程,可以使用此技术实现进程间通信。那么如何使用aidl呢?
1. 创立aidl文件
在src/main目录下面右键创立aidl文件,androidStudio会给我们自动生成相应的目录和示例文件。
自动生成的目录和文件
2. 创立需要的传输的实体类bean
需要知道 : aidl中支持java的8中基础数据类型和Charsequence、String、List、Map。引用对象类型需要序列化,且仅支持parcelable方式的序列化。
public class Book implements Parcelable { private String name; private float price; public Book(Parcel in) { this.name = in.readString(); this.price = in.readFloat(); } public static final Creator<Book> CREATOR = new Creator<Book>() { @Override public Book createFromParcel(Parcel in) { return new Book(in); } @Override public Book[] newArray(int size) { return new Book[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeFloat(price); }}3. 创立公告实体类的aidl文件
第二点说了aidl只支持固定的几种数据类型,对于引用类型,假如想支持的话,需要创立对应的xxx.aidl的文件,而后在里面公告该实体类。一个aidl文件对应一个实体类。必需这样,才能正常编译运行程序。比方在Book.aidl文件中公告Book对象
需要知道:aidl文件中,假如要访问其余文件对象,需要import 该文件包名。即便他们在同一个包下(这个和kotlin、dart语言相似,一个文件相当于包的访问权限)
// Book.aidlpackage com.example.bangbangqiu.bluetoothapp;// Declare any non-default types here with import statementsimport com.example.bangbangqiu.bluetoothapp.Book;parcelable Book;4. 修改IMyAidlInterface.aidl文件
这个文件也是最关键的文件。在这个接口文件中公告方法,它作为服务进程与用户端进程之间的桥梁。
公告的方法和接口方法公告一样 只要要 返回类型 + 方法名的格式。
会看到 参数中有带关键字in(定向tag)。在aidl中方法参数 可以用 in out inout修饰,in表示数据由用户端流向服务器端,out反之,inout数据双向都可传输。
interface IMyAidlInterface { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ List<Book> getBooks(); void addBook(in Book book); void feedBack();}到此aidl部分已经完成了,编译之后,会在build/generate/source/aidl文件下面看到ide自动生成的aidl的实现类。下面就需要写用户端和服务端的代码逻辑了
5. 创立服务进程
创立service并使其在名为remote的进程中运行
public class AIDLService extends Service { List<Book> books = new ArrayList<>(); IMyAidlInterface.Stub stub = new IMyAidlInterface.Stub() { @Override public List<Book> getBooks() throws RemoteException { return books; } @Override public void addBook(Book book) throws RemoteException { books.add(book); } @Override public void feedBack() throws RemoteException { Log.d("AIDLService", "feedBack: is running"); } }; @Nullable @Override public IBinder onBind(Intent intent) { return mBinder; } public IBinder mBinder = new MyBinder(); public class MyBinder extends Binder { public void feedBack() { Log.d("AIDLService", "feedBack: is running"); } }}AndroidManifest.xml:
<service android:name=".AIDLService" android:process=".remote" android:exported="true"> <intent-filter> <action android:name="com.bluetoothapp.aidl"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </service>假如熟习service的bind方式,就会觉得上面代码其实和写个普通service没啥区别。只是返回的对象就是AIDL中创立的对象。
6. 写用户端逻辑
在用户端bindService就可,就是普通的bindservice写法。
if (serviceConnection == null) { serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service); Toast.makeText(SecondActivity.this, "onservice_connect", Toast.LENGTH_SHORT).show(); } @Override public void onServiceDisconnected(ComponentName name) { } }; Intent intent = new Intent(); intent.setAction("com.bluetoothapp.aidl"); intent.setClass(this, AIDLService.class); bindService(intent, serviceConnection, Service.BIND_AUTO_CREATE); }编译可能会报错,如下
image.png
由于gradle构建的时候只会把src/main/java目录作为java代码目录,所以要加上
sourceSets { main { java.srcDirs = ['/src/main/java', 'src/main/aidl'] } }注意:bindService可能会发现报错,由于在android 5.0后强制要显式启动service 。
当前示例是在同个项目,在不同项目需要将aidl的目录拷贝一份
最后想说:写的比较通俗,主要是自我梳理和帮助没使用过的快速理解。