AIDL(Android Interface Definition Language)是一种 IDL 语言,用于生成可以在 Android 设备上两个进程之间进行进程间通信(IPC)的代码。 通过 AIDL,可以在一个进程中获取另一个进程的数据和调用其暴露出来的方法,从而满足进程间通信的需求。通常,暴露方法给其他应用进行调用的应用称为服务端,调用其他应用的方法的应用称为客户端,客户端通过绑定服务端的 Service 来进行交互。
下面介绍AIDL的使用方法。
1、创建AIDL文件
客户端和服务端都需要创建,我们先在服务端中创建,然后复制到客户端即可。在 Android Studio 中右键点击新建一个 AIDL 文件,系统就会默认创建一个 aidl 文件夹,文件夹下的目录结构即是工程的包名,AIDL 文件就在其中,如图所示:
文件名称为IImoocAidl,我们删除里面默认的basicTypes方法,新增个add方法,用来计算两个数的和。
2、实现接口
创建或修改过 AIDL 文件后需要 build 下工程,Android SDK 工具会生成以 .aidl 文件命名的 .java 接口文件(例如,IImoocAidl.aidl 生成的文件名是 IIImoocAidl.java),在进程间通信中真正起作用的就是该文件。
3、在服务端公开接口
在为服务端实现接口后,需要向客户端公开该接口,以便客户端进行绑定。创建 Service 并实现 onBind(),从而返回生成的 Stub 的类实例。
我们还需要在 Manefest 文件中注册我们创建的这个 Service,否则客户端无法绑定服务。
4、客户端调用IPC方法
当客户端(如 Activity)调用 bindService() 以连接此服务时,客户端的 onServiceConnected() 回调会接收服务端的 onBind() 方法所返回的 binder 实例。
客户端还必须拥有接口类的访问权限,因此如果客户端和服务端在不同应用内,则客户端应用的 src/ 目录内必须包含 .aidl 文件(该文件会生成 android.os.Binder 接口,进而为客户端提供 AIDL 方法的访问权限)的副本。所以我们需要把服务端的 aidl 文件夹整个复制到客户端的 java 文件夹同个层级下,不需要改动任何代码。
我们在客户端的activity创建如下布局
<EditText
android:id="@+id/edd_num1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+" />
<EditText
android:id="@+id/edd_num2"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="=" />
<EditText
android:id="@+id/edd_res"
android:layout_width="match_parent"
android:enabled="false"
android:layout_height="wrap_content" />
<Button
android:id="@+id/btn_add"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="AIDL远程计算" />
客户端代码如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private EditText mEtNum1;
private EditText mEtNum2;
private EditText mEtNumRes;
private Button mBtnAdd;
IImoocAidl iImoocAidl;
private ServiceConnection conn = new ServiceConnection() {
// 绑定上服务
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 拿到了远程的服务
iImoocAidl = IImoocAidl.Stub.asInterface(service);
}
// 断开服务
@Override
public void onServiceDisconnected(ComponentName name) {
//回收资源
iImoocAidl = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
// 软件已启动就绑定服务
bindService();
}
private void initView() {
mEtNum1 = findViewById(R.id.edd_num1);
mEtNum2 = findViewById(R.id.edd_num2);
mEtNumRes = findViewById(R.id.edd_res);
mBtnAdd = findViewById(R.id.btn_add);
mBtnAdd.setOnClickListener(this);
}
@Override
public void onClick(View v) {
int num1 = Integer.parseInt(mEtNum1.getText().toString().trim());
int num2 = Integer.parseInt(mEtNum2.getText().toString().trim());
try {
// 调用远程的服务
if (null != iImoocAidl) {
int res = iImoocAidl.add(num1, num2);
mEtNumRes.setText(res + "");
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
private void bindService() {
// 获取到服务端
Intent intent = new Intent();
// 新版本 必须 显示Intent 启动绑定服务
intent.setComponent(new ComponentName("com.example.aidl", "com.example.aidl.IRemoteService"));
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
}