AIDL简介
在Android
中,进程之间原则上是不能进行通信的。但偏偏Android
从四大组件到框架、底层到处都是IPC的影子。AIDL
就是IPC
方式之一。
AIDL
(Android
接口定义语言) 是 Android
提供的一种进程间通信 (IPC
) 机制。
我们可以使用它在两个不同进程之间的Client
与Server
进行通信。
使用AIDL步骤
使用aidl
大致分为三块,编写aidl
生成必要文件。创建Client
和Server
使用。
- 编写
AIDL
- 创建
Bean
类,实现Parcelable
接口(便于序列化、反序列化)。 - 编写
aidl
文件 - 生成
java
文件
- 创建
- 编写
Server
- 创建
Service
,在其中创建上面生成的Binder
对象实例,实现接口定义的方法 - 在
onBind()
中返回
- 创建
- 编写
Client
- 实现
ServiceConnection
接口,在其中拿到AIDL
类 - 绑定服务
- 调用
aidl
中的请求并等待返回结果
- 实现
步骤一:编写AIDL
- 创建
Bean
类,实现Parcelable
接口(便于序列化、反序列化)
package com.cx.aidldemo.bean;
import android.os.Parcel;
import android.os.Parcelable;
/**
* 书的实体类
*/
public class Book implements Parcelable {
private String name;
private double price;
public Book() {}
public Book(String name, double price) {
this.name = name;
this.price = price;
}
protected Book(Parcel in) {
name = in.readString();
price = in.readDouble();
}
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.writeDouble(price);
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
-
编写
aidl
文件- 不过在编写aidl文件之前,要拥有
aidl
目录。没有的话就创建。 - 创建方式:在
main
目录下创建aidl
目录,并在aidl
目录下创建和java
目录下子目录一样的包名。
- 不过在编写aidl文件之前,要拥有
- 创建Bean类的aidl
// Book.aidl
package com.cx.aidldemo.bean;
parcelable Book;
- 创建接口的aidl
// IMyService.aidl
package com.cx.aidldemo;
import com.cx.aidldemo.bean.Book;
interface IMyService {
/**
* 添加一个书
*/
void addBook(in Book book);
/**
* 获取所有书
*/
List<Book> getBookList();
}
注意:
- 这个
Book.aidl
的包名要和实体类包名一致。- 除了基本数据类型,其他类型的参数都需要标上方向类型:in(输入),out(输出),inout(输入输出)。
- 非基本类型的数据需要导入它的全路径。即便是同级目录下。
- 生成
java
文件- 方式:
Build -> Make Project
- 然后就会在
app/build/generated/source/aidl/package_name/
下生成一个Java
文件
- 方式:
现在我们就可以通过它来进行IPC通信了。
步骤二:编写Server
- 创建
Service
,在其中创建上面生成的Binder
对象实例,实现接口定义的方法 - 在
onBind()
中返回
public class MyAIDLService extends Service {
private List<Book> books;
public MyAIDLService() {
}
private IBinder mIBinder = new IMyService.Stub() {
@Override
public void addBook(Book book) throws RemoteException {
books.add(book);
}
@Override
public List<Book> getBookList() throws RemoteException {
return books;
}
};
@Override
public IBinder onBind(Intent intent) {
books = new ArrayList<Book>();
return mIBinder;
}
}
配置清单:
<service
android:name=".MyAIDLService"
android:enabled="true"
android:exported="true"
android:process=":aidl"></service>
-
enabled属性
- 默认为
true
- 其值为
true
,则说明应用程序组件可以被Android
系统自动实例化 - 如果为
false
,则说明实例化组件的工作需要手工完成。
- 默认为
-
exported属性
- 是否支持其它应用调用当前组件
- 如果包含有
intent-filter
默认值为true
;没有intent-filter
默认值为false
-
process属性
- 如果该属性里设置的名字以冒号开头(:),那么在需要的时候它将生成该应用程序的一个私有新进程。
服务端实现了接口,在 onBind()
中返回这个 Binder,客户端拿到就可以操作数据了。
步骤三:编写Client
- 实现
ServiceConnection
接口,在其中拿到AIDL
类
public class MainActivity extends AppCompatActivity {
private IMyService iMyService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
// onBind连接后会返回 Binder,也就是iBinder参数
// 将其转换成 AIDL,在不同进程会返回代理对象
iMyService = IMyService.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
iMyService = null;
}
};
}
- 绑定服务
Intent intent1 = new Intent(getApplicationContext(), MyAIDLService.class);
// 绑定服务
bindService(intent1, connection, BIND_AUTO_CREATE);
- 调用
aidl
中的请求并等待返回结果
/**
* 添加一本书
* @param view
*/
public void onAddBook(View view) {
Book book = new Book("Android_" + System.currentTimeMillis(), 100);
try {
iMyService.addBook(book);
} catch (RemoteException e) {
e.printStackTrace();
}
}
/**
* 获取所有书籍
* @param view
*/
public void onGetBooks(View view) {
try {
tvResult.setText(iMyService.getBookList().toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
日志打印:
服务端进程名.png客户端进程名.png
运行结果:
运行结果.gif
网友评论