安卓接口描述语言AIDL
全称:Android Interface definition language
作用:进程间的通信接口(实现两个进程数据共享)
IBinder可以进行进程间和跨进程间的调用
定义转:https://www.jianshu.com/p/29999c1a93cd
AIDL 意思即 Android Interface Definition Language,翻译过来就是Android接口定义语言,是用于定义服务器和客户端通信接口的一种描述语言,可以拿来生成用于IPC的代码。从某种意义上说AIDL其实是一个模板,因为在使用过程中,实际起作用的并不是AIDL文件,而是据此而生成的一个IInterface的实例代码,AIDL其实是为了避免我们重复编写代码而出现的一个模板
设计AIDL这门语言的目的就是为了实现进程间通信。在Android系统中,每个进程都运行在一块独立的内存中,在其中完成自己的各项活动,与其他进程都分隔开来。可是有时候我们又有应用间进行互动的需求,比较传递数据或者任务委托等,AIDL就是为了满足这种需求而诞生的。通过AIDL,可以在一个进程中获取另一个进程的数据和调用其暴露出来的方法,从而满足进程间通信的需求
通常,暴露方法给其他应用进行调用的应用称为服务端,调用其他应用的方法的应用称为客户端,客户端通过绑定服务端的Service来进行交互
一、远程启动服务
ServiceDemo实现同一个进程间启动、停止、绑定、解绑服务等操作
依次点击
- 启动服务
- 绑定服务
- 解绑服务
- 停止服务
/com.demo.servicedemo D/MyService-vv: onCreate:
/com.demo.servicedemo D/MyService-vv: onStartCommand:
/com.demo.servicedemo D/MyService-vv: onBind:
/com.demo.servicedemo D/MainActivity-vv: onServiceConnected:
/com.demo.servicedemo D/MainActivity-vv: 当前进度是: 2
/com.demo.servicedemo D/MyService-vv: onUnbind:
/com.demo.servicedemo D/MyService-vv: onDestroy:
MyService.java
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
/**
* <p>文件描述:<p>
* <p>作者:Mr-Donkey<p>
* <p>创建时间:2018/11/25 14:03<p>
* <p>更改时间:2018/11/25 14:03<p>
* <p>版本号:1<p>
*/
/**
* Service进行同一个进程的通信
*/
public class MyService extends Service {
private static final String TAG = "MyService-vv";
private int i;
public static boolean IsBinder = false;
public MyService() {
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate: ");
//开启一个线程(从1数到100),用于模拟耗时的任务
new Thread() {
@Override
public void run() {
super.run();
try {
for (i = 1; i <= 100; i++) {
sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
/**
* 绑定服务后会在on
*
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind: ");
IsBinder = true;
return new MyBinder();
}
/**
* Binder是IBinder的空实现类
* 提供一个方法用于获取当前计数的进度
*/
public class MyBinder extends Binder {
public int getProcess() {
return i;
}
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind: ");
IsBinder = false;
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: ");
}
}
在AndroidManifest.xml中 注册Service
android:exported="true" 表明当前Service对其他App开放
并且要设置action。
<application
....
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.demo.myservice" />
</intent-filter>
</service>
</application>
MainActivity.java
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity-vv";
private MyService.MyBinder mb;
private ServiceConnection conn = new ServiceConnection() {
//当客户端正常连接着服务时,执行服务的绑定操作会被调用
//此时传来的IBinder对象是onbinder的返回的对象
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected: ");
//将IBinder对象转成MyBinder
mb = (MyService.MyBinder) service;
//调用MyBinder中的获取进度的方法:实现监控
int process = mb.getProcess();
Log.d(TAG, "当前进度是: " + process);
}
//当客户端和服务的连接丢失了
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "onServiceDisconnected: ");
}
};
//IBinder
//ServicerConnection:用于绑定客户端和Service
//进度监控
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/**
* 按钮点击事件
*
* @param v
*/
public void operate(View v) {
switch (v.getId()) {
case R.id.start:
//启动服务:创建-->启动-->销毁
//如果服务已经创建了,后续重复启动,操作的都是同一个服务,不会再重新创建了,除非你先销毁它
Intent it1 = new Intent(this, MyService.class);
startService(it1);
break;
case R.id.stop:
Intent it2 = new Intent(this, MyService.class);
stopService(it2);
break;
case R.id.bind:
//绑定服务:最大的 作用是用来实现对Service执行的任务进行进度监控
//如果服务不存在: onCreate-->onBind-->onUnbind-->onDestory
// (此时服务没有再后台运行,并且它会随着Activity的摧毁而解绑并销毁)
//服务已经存在:那么bindService方法只能使onBind方法被调用,而unbindService方法只能使onUnbind被调用
Intent it3 = new Intent(this, MyService.class);
bindService(it3, conn, BIND_AUTO_CREATE);
break;
case R.id.unbind:
//解绑服务
if (MyService.IsBinder)
unbindService(conn);
break;
}
}
}
新建一个AIDLDemo来远程启动服务
主要是通过显示声明Intent来操作另外一个Servicedemo app
确保Servicedemo的AndroidManifest.xml中配置写正确,还有两个app同时运行在手机上
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/**
* android5.0后要通过显式声明Intent来实现远程启动服务
*/
public void operate(View view) {
switch (view.getId()) {
case R.id.start:
Intent it1 = new Intent();
it1.setAction("com.demo.myservice");
it1.setPackage("com.demo.servicedemo");
startService(it1);
break;
case R.id.stop:
Intent it2 = new Intent();
it2.setAction("com.demo.myservice");
it2.setPackage("com.demo.servicedemo");
stopService(it2);
break;
case R.id.bind:
Intent it3 = new Intent();
it3.setAction("com.demo.myservice");
it3.setPackage("com.demo.servicedemo");
bindService(it3, conn, BIND_AUTO_CREATE);
break;
case R.id.unbind:
//解绑服务
unbindService(conn);
break;
}
}
}
这样一来就可以远程操作了。
二、远程服务通信
AIDL的使用
AIDL 作为进程之间通信的桥梁,使用 AIDL 需要遵守一些规则,包括数据的特定要求。
编写 AIDL 文件需要遵守如下语法规则:
1、 文件后缀名必须为.aidl;
2、 AIDL 默认支持的数据类型如下: byte,short,int,long,float,double,boolean,char,String,CharSequence, List,Map(List、Map 中定义的类型也需要是 AIDL 支持的)
3、 AIDL 也支持自定义实体类,但对实体类的操作是有要求的:
- 1) 创建类 MyBean,需要实现 Parcelable 接口
- 2) aidl 目录下创建相同包名的 MyBean.aidl 文件,并添加如下代 码:
package 包名;
parcelable MyBean;
- 3) 在其他 aidl 文件中,添加如下导包语句,引入 MyBean 类:
import 包名.MyBean;
下面是默认支持数据类型的实现:
通过AIDL,可以在一个进程中获取另一个进程的数据和调用其暴露出来的方法,从而满足进程间通信的需求
- 创建AIDL文件
- 自动生成AIDL的java文件
- 使用AIDL
在servicedemo中
一、创建AIDL文件
main文件夹右键New——>AIDL——>AIDL File
然后就在main文件夹下生成一个aidl文件夹这个文件夹中又有一个和java中的包名一致的包,里面生成自定义的.aidl文件
IMyAidlInterface.aidl 里面的内容
可以看见其实一个接口,可以写你想要实现的接口方法,以下是默认的,那么我添加一个获取进度的方法getProcess()
// IMyAidlInterface.aidl
package com.demo.servicedemo;
// Declare any non-default types here with import statements
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);
}
添加方法后(去不去掉默认的方法都可以) 我这里去掉了
// IMyAidlInterface.aidl
package com.demo.servicedemo;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
void getProcess();
}
2.自动生成AIDL的java文件
Builde——>Rebuild Project 就可以自动生成aidl的java文件了
位于:build——>generated——>source——>aidl——>debug下
这是自动生成的aidl的java文件,不用看得懂,其实就是实现进程间通信的具体实现
注意:
public static abstract class Stub extends android.os.Binder implements com.demo.servicedemo.IMyAidlInterface
1.其实Stub抽象类是继承了Binder(是IBinder的一个空实现类),那么Stub也是IBinder的子类
就可以在 服务绑定的时候,返回这个Stub对象来替换之前的MyBinder();
修改后的onBind@Nullable @Override public IBinder onBind(Intent intent) { Log.d(TAG, "onBind: "); IsBinder = true; return new MyBinder(); } /** * Binder是IBinder的空实现类 * 提供一个方法用于获取当前计数的进度 */ public class MyBinder extends Binder { public int getProcess() { return i; } }
@Nullable @Override public IBinder onBind(Intent intent) { Log.d(TAG, "onBind: "); IsBinder = true; return new IMyAidlInterface.Stub() { @Override public void getProcess() throws RemoteException { Log.d(TAG, "getProcess: " + i); } }; }
返回一个Stub对象
2.public static com.demo.servicedemo.IMyAidlInterface asInterface(android.os.IBinder obj)
asInterface是Stub特别重要的一个方法
可以通过传入Stub对象来获取com.demo.servicedemo.IMyAidlInterface的实例,进而调用在com.demo.servicedemo.IMyAidlInterface自定义的方法来获取数据
在绑定服务成功后,onServiceConnected中收到onBind()返回的IBinder对象
此时可以通过
IMyAidlInterface im = IMyAidlInterface.Stub.asInterface(service); //获取自定义方法 im.getProcess();
来获取当前进度
完整代码:
private ServiceConnection conn = new ServiceConnection() { //当客户端正常连接着服务时,执行服务的绑定操作会被调用 //此时传来的IBinder对象是onbinder的返回的对象 @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, "onServiceConnected: "); try { //拿到IMyAidlInterface对象实例 IMyAidlInterface im = IMyAidlInterface.Stub.asInterface(service); //获取自定义方法 im.getProcess(); } catch (RemoteException e) { e.printStackTrace(); } } //当客户端和服务的连接丢失了 @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "onServiceDisconnected: "); }
IMyAidlInterface.java
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: /Users/mac/Downloads/Android3Step1/servicedemo/src/main/aidl/com/demo/servicedemo/IMyAidlInterface.aidl
*/
package com.demo.servicedemo;
// Declare any non-default types here with import statements
public interface IMyAidlInterface extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.demo.servicedemo.IMyAidlInterface
{
private static final java.lang.String DESCRIPTOR = "com.demo.servicedemo.IMyAidlInterface";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.demo.servicedemo.IMyAidlInterface interface,
* generating a proxy if needed.
*/
public static com.demo.servicedemo.IMyAidlInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.demo.servicedemo.IMyAidlInterface))) {
return ((com.demo.servicedemo.IMyAidlInterface)iin);
}
return new com.demo.servicedemo.IMyAidlInterface.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getProcess:
{
data.enforceInterface(DESCRIPTOR);
this.getProcess();
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.demo.servicedemo.IMyAidlInterface
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public void getProcess() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getProcess, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getProcess = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void getProcess() throws android.os.RemoteException;
}
在AIDLDemo中
- 同样创建一样的aidl文件
- 生成aidl的java文件
- 使用aidl
copy main文件夹下的aidl文件夹,然后rebuild project生成java文件
这样是保持aidl的匹配一致
那么在AIDLDemo中的MainActivity中就可以获取到servicedemo中的进度值了
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
IMyAidlInterface im = IMyAidlInterface.Stub.asInterface(service);
im.getProcess();
Log.d(TAG, "onServiceConnected: AIDLDemo拿到进度值");
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
在AIDLDemo中依次进行启动、绑定、解绑、停止服务的log
servicedemo的log
/com.demo.servicedemo D/MyService-vv: onCreate:
/com.demo.servicedemo D/MyService-vv: onStartCommand:
/com.demo.servicedemo D/MyService-vv: onBind:
/com.demo.servicedemo D/MyService-vv: getProcess: 2
/com.demo.servicedemo D/MyService-vv: onUnbind:
/com.demo.servicedemo D/MyService-vv: onDestroy:
AIDLDemo的log
/com.demo.android3step2 D/MainActivity-vv: onServiceConnected: AIDLDemo拿到进度值
进行进程间对象的传递也是一样的性质:
更多内容参考: