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.aidl
package com.example.bangbangqiu.bluetoothapp;
// Declare any non-default types here with import statements
import 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的目录拷贝一份
最后想说:写的比较浅显,主要是自我梳理和帮助没使用过的快速了解。
网友评论