Android AIDL笔记

在Android系统中,通常一个进程不能访问其它进程的内存。AIDL(Android Interface definition language)允许定义客户端和服务端都同意为了彼此之间的通信使用进程间通信(IPC)的编程接口,其本质是用Binder实现的。

以下为一个简单的AIDL实例

服务端

1.新建AIDL文件

首先用Android Studio 新建一个Android工程,这里命名为com.example.AIDL_Server。在工程目录下,“右键“->”New”->”AIDL File”,这里接口命名为“MyAidl”,每个.aidl文件必须定义一个接口并且只需要接口声明。

这里定义接口方法为Add,返回客户端输入的两个数之和。MyAidl.aidl文件如下:

1
2
3
4
5

package com.example.aidl_server.myapplication;
interface MyAidl {
int Add(int a,int b);
}

接着Make一下,自动会生成对应的Java文件,生成的文件名和.aidl文件名匹配,但扩展名为.java,本质为Binder实现。

###2.实现接口
上一步定义好了接口和Add方法,需要进一步实现。新建一个Service,在Service中新建一个内部类MyAidl.Stub,在该类中实现Add接口。

3.对外暴漏接口

在Service中的onBind函数中返回接口,另外还需注意在manifest文件中声明Service接口,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

public class Add extends Service {

private MyAidl.Stub mRemote = new MyAidl.Stub(){
@Override
public int Add(int a, int b) throws RemoteException {
return a+b;
}
};

public Add() {
}

@Override
public IBinder onBind(Intent intent) {
return mRemote;
}
}

客户端

1.复制AIDL文件

当客户端与服务器不在同一个应用程序中时,客户端必须也复制一份AIDL文件到其目录下,并且包的路径和名称不能改动,这里直接将服务端AIDL目录整体复制到客户端main目录下,同样编译后生成对应的Java文件。

2.新建ServiceConnection对象

当一个客户端(例如activity)调用bindService()连接到这个service,客户端的onServiceConnected()回调接收到由service的onBind()返回的mBinder实例。

import远程AIDL包,定义一个远程AIDL对象,新建一个ServiceConnection对象,在其ServiceConnection()函数中将接收到的Binder进行转换。

3.远程调用

调用Add进行加法运算,注意捕获RemoteException异常。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

public class MainActivity extends AppCompatActivity {

public MyAidl mRemote = null;


public ServiceConnection sc= new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

mRemote = MyAidl.Stub.asInterface(iBinder);
System.out.println("-----Connect---------");

}

@Override
public void onServiceDisconnected(ComponentName componentName) {
mRemote=null;

}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Intent intent = new Intent("com.example.aidl_server.myapplication.Add");

bindService(intent,sc, Context.BIND_AUTO_CREATE);



Button bt = (Button) findViewById(R.id.button);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
System.out.println(mRemote.Add(1, 2));
Toast.makeText(MainActivity.this, String.valueOf(mRemote.Add(1, 2)),Toast.LENGTH_SHORT).show();
}
catch (RemoteException e){
e.printStackTrace();
}

}
});


}
}

遇到的坑

  • 服务端的Service需要启动,我是在MainActivity 里new Add()才启动服务
  • bindService时,Intent名字要对应
  • 客户端直接在OnCreate函数里进行远程调用失败,加了个Button在onClick里调用正常

参考链接

  1. Android开发指南——进程间通信AIDL
  2. android中的AIDL进程间通信
  3. AIDL binder框架浅析(比较详细)
  4. 另一篇比较详细的