今天聊聊AIDL,Android Interface Definition Language(安卓接口定义语言),即安卓进程间通信。
首先我们知道,狭义来说,一个应用对应一个进程。而如果想跨应用交互,那就涉及到进程间通信,而安卓四大组件都代表一种进程间通信的方式。
但是我们今天说的AIDL,则是通过Service,为什么选择聊Service呢 ?其一 ,因为它的自定义程度最高。其二 ,Service的优先级高。
我们简单理一下思路 。使用AIDL作为进程间通信的方式,那也就是说,我们需要至少两个应用,一个作通信的服务端,一个作通信的客户端。(当然,可以有不止一个客户端,也可以有不止一个服务端)。
那客户端与服务端如何跨进程通信呢 ?这就需要它们有一个共同的通信标准,就是AIDL,姑且理解为一种协议,服务端和客户端各自定义好一摸一样的协议(包括包名/类名/方法名) ,然后服务端提供具体的实现,客户端执行调用。
比如 :客户端通过服务端提供的XX方法 得到了XX结果。
听上去很像接口,有没有?其实个人愚见也是如此,因为接口是一个翻泛概念,你给我提供一个途径,我通过这个途径把参数给你,你处理后把结果给我。符合该模式的,我觉得都可以归为接口。
以下做一个简单的示例,(我们今天不谈IBinder,如果你想更深刻的理解 AIDL,建议还是去认真揣摩揣摩IBinder)
示例的服务端提供一个接口IMyLog ,里面有一个方法sysOut,接受一个String参数,并Log出来。客户端则是去绑定服务端,并调用IMyLog接口的这个方法,传入参数,让其执行。
步骤分为两部份:
第一部分:服务端:
1.首先创建一个文件夹,在其中定义一个AIDL类,如图:
注意,这里是AS,所以生成AIDL文件夹的方式不太一样。如果是Eclipse,直接在java路径下生成就好。
2.创建一个Service类:
public class MainService extends Service {
private IBinder iBinder = new IMyLog.Stub(){
@Override
public void sysOut(String content) throws RemoteException {
Log.i("aidl","service get " + content);
}
};
@Override
public IBinder onBind(Intent intent) {
return iBinder;
}
@Override
public void onCreate() {
super.onCreate();
Log.i("aidl","service create");
}
}
第二部分:客户端:
1.首先创建一个文件夹,在其中定义一个AIDL类,如图:
注意:这个AIDL类必须和服务端的AIDL一摸一样,包括文件夹路径。
2.创建一个客户端Activity:
public class MainActivity extends AppCompatActivity {
private IMyLog iMyLog;
//ServiceConnection,在绑定成功时返回AIDL的接口IMyLog
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("aidl","conn is success");
iMyLog = IMyLog.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i("aidl","disconn is success");
iMyLog = null;
}
};
@Override
protected void onDestroy() {
Log.i("aidl","on Destroy");
unbindService(conn);
super.onDestroy();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
doBind();
}
//隐式Intent绑定服务端Service,获得ServiceConnection
private void doBind() {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.lebang.myservice","com.lebang.myservice.MainService"));
bindService(intent,conn, Context.BIND_AUTO_CREATE);
}
//Button的点击事件,点击时调用服务端AIDL方法,传入参数“today I ...”
public void doThing (View view){
Log.i("aidl","client send message");
try {
iMyLog.sysOut(": today I do the aidl");
} catch (RemoteException e) {
e.printStackTrace();
Log.i("aidl","client error");
}
}
}
然后启动模拟器,先确保安装上服务端程序,再执行客户端程序。点击Button,会发现,在服务端程序的Log下会打印出:
service get : today I do the aidl
最末,做个简单介绍,如果你发现如上操作会崩溃,原因可能是Manifest文件中未配置可通信。解决方法有两种:
1.在客户端服务端Manifest主标签下配置属性 sharedUserId :
如: android:sharedUserId="com.lebang"
2.在服务端Service中配置属性:如:
<service
android:name=".MainService"
android:exported="true"/>
抽时间写的,没有整理好语言,谬误之处,欢迎指出。