前言:
今天看AIDL基础和原理,在学习过程中遇到一些问题,寻找了好些文章都没有得到一些解决的方案,后来找到了解决的方案,因此在此整理下相关的知识,做个笔记,也分享给各位童鞋。
概要:
本文主要介绍AIDL的含义,作用以及入门的案例,本文还会涉及到Service,Binder等相关知识,本文不做详细介绍,请自行查找资料学习。这位大神写的Binder中transact和onTransact的区别可以开下:
一,什么是AIDL
AIDL是Android中进程间通信方式之一,Android interface definition language的简称。
二,AIDL的作用
进程间通信又叫IPC(Inter-Process Communication),因为进程间资源不能共享,所以每个系统都有自己的一套IPC机制,Android是基于Linux内核的操作系统,但是并没有继承Linux的IPC机制,有自己的一套IPC机制。AIDL作为IPC方式的一种,底层基于Binder机制,作用就是在自己的APP可以调用别的APP中的方法,简单的理解为在自己的APP里绑定别的APP的service,这样就可以实现和别的APP的交互。
三,AIDL实现原理
这里简单介绍下AIDL在android中是怎样实现一个APP调用另一个APP的Service的。客户端APP会通过bindService绑定服务端APP的一个Service,然后Android系统就会调用这个Service中的onBinder方法,该方法返回一个用于和Service交互的IBinder对象。bindService是异步执行的,bindService方法会立即返回,但是不会返回IBinder给客户端,客户端APP必须创建一个ServiceConnection对象,传给bindService。ServiceConnection包含一个回调方法onServiceConnected,系统调用这个返回IBinder对象,客户端APP使用这个IBinder对象调用Service。
四,简单示例
首先创建一个服务端的android项目,创建AIDL文件,右击MainActivity所在目录New->AIDL,输入文件名,就会生成一个AIDL文件,如图:
basicTypes方法是说明有哪些默认支持的类型,无视,自己定义一个供调用的接口方法:
interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
/*void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);*/
String getMessage();
}
然后sync project一下
(很重要),Tools -> Android ->Sync project ***。
现在我们新建一个Service,里面包含一个内部类,继承自刚才创建的AIDL中的Stub类,并实现接口方法,onBinder方法里面返回该内部类的对象。
public class MyService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
class MyBinder extends IMyAidlInterface.Stub{
@Override
public String getMessage() throws RemoteException {
return "return success!";
}
}
}
然后在AndroidManifest.xml文件中注册隐式service并设置action。
<service android:name=".MyService">
<intent-filter >
<action android:name="com.example.liujibin.testaidl1.MyService"></action>
</intent-filter>
</service>
到此提供服务的APP创建完成了。然后我们新建一个客户端APP,并将刚才服务端APP中创建的AIDL文件连着整个aidl文件夹一起复制到客户端APP中,然后sync project一下
(很重要)。
AIDL文件的包名和服务端中AIDL文件的包名一样。
然后我们在客户端APP中的Activity中实现绑定服务端Service,调用实现的接口方法。
public class MainActivity extends AppCompatActivity {
private Button btn;
private IMyAidlInterface iMyAidlInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn = (Button) findViewById(R.id.btn);
Intent intent = new Intent();
intent.setAction("com.example.liujibin.testaidl1.MyService");
intent.setPackage("com.example.liujibin.testaidl1");
bindService(intent,connection,BIND_AUTO_CREATE);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
Toast.makeText(MainActivity.this,""+iMyAidlInterface.getMessage(),Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
iMyAidlInterface = null;
}
};
}
在这过程中遇到过一个坑,很多基础教程介绍的Intent只调用了setAction,这样我在android4.4的系统上运行没有问题,但是在android5.0上bindService就报错,需要添加一个setPackage设置服务端APP的包名才能正常使用。因为android5.0版本以后隐式启动被禁止,需要实现setPackage。
然后先安装下服务端APP,在运行客户端APP,点击按钮,success。