AIDL(Android Interface Definition Language):字面翻译 Android接口定义语言。简而言之,AIDL 是Android实现 IPC(跨进程通信)的开发规则与方法
AIDL官方文档:aidl原理 / 编组与解编 / 默认支持的数据类型 / 开发规则
相关概念
IPC:跨进程通信(interprocess communication)
Binder机制:在Android系统中,个个应用程序都运行在自己的进程中,进程之间一般是无法直接进行数据交换的, 而为了实现跨进程通信,Android给我们提供了Binder机制。进一步了解Binder机制,可以参考 article1,article2
Binder机制的实现就采用了AIDL。简而言之,(初步理解)由于进程A无法直接访问另一个进程B的内存空间,而Android系统可以访问他们的内存空间,所以Android系统就充当了跨进程通信的中介,进程B把自己的方法托付给系统。然后,间接地,进程A(client)就可以访问进程B了
Binder类实现了IBinder接口;bindService--onBind--onServiceConnected就用到了IBinder接口与Binder类
一般情况下一个程序只有一个进程,这个程序的所有组件(四大组件)都在该进程中的主线程中跑。跨进程通信可以算是远程访问,涉及多个进程。本地service默认情况下运行在当前进程的主线程中,远程service运行在另一个进程中。
注意:只有在需要不同应用的客户端通过 IPC 方式访问服务,并且希望在服务中进行多线程处理时,您才有必要使用 AIDL。如果您无需跨不同应用执行并发 IPC,则应通过实现 Binder 来创建接口;或者,如果您想执行 IPC,但不需要处理多线程,请使用 Messenger 来实现接口。无论如何,在实现 AIDL 之前,请您务必理解绑定服务。
IDE:Android studio
1.在serverAPP中编写aidl文件,在src/main/aidl/com.clc.app5包下现建 IRemoteService.aidl(编写规则参照官网)
2.build项目,自动生成接口文件 IRemoteService.java,可在 build/generator/.../com.clc.app5包下查看
3.在service中实现接口,并将接口对象通过onBind()方法返回给客户端clientAPP的onServiceConnected()方法
4.在客户端clientAPP中获取到接口对象,调用其方法
service和客户端不在一个app中,否则用不着aidl
初步理解
activity与service的通信,归根结底是通过调用IRemoteService.Stub中的方法实现的
service--data-->activity:设置方法的返回值,在service中返回对象,在activity中获取
activity--data-->service:设置方法的参数,在activity调用时传入,在service中获取当某个组件(client)调用bindService方法绑定同一个APP中的service时,client自然可以调用service的onBind方法返回的对象。当client和service处在两个APP时,还想实现这种处理,就要用AIDL编写两个APP都认可的接口。
在serverAPP中
package com.clc.app5;
import android.os.Parcel;
import android.os.Parcelable;
public class City implements Parcelable {
public int cityId;
public String cityName;
public City() {
}
public City(int cityId, String cityName) {
this.cityId = cityId;
this.cityName = cityName;
}
/*
解包
*/
protected City(Parcel in) {
cityId = in.readInt();
cityName = in.readString();
}
public static final Creator CREATOR = new Creator() {
@Override
public City createFromParcel(Parcel in) {
return new City(in);
}
@Override
public City[] newArray(int size) {
return new City[size];
}
};
@Override
public int describeContents() {
return 0;
}
/*
打包
*/
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(cityId);
parcel.writeString(cityName);
}
}
================================
『src/main/aidl/com.clc.aidl.City.aidl』
// City.aidl
package com.clc.app5;
// Declare any non-default types here with import statements
parcelable City;
=====================================
『src/main.aidl/com.clc.aidl.IRemoteService.aidl』
// IRemoteService.aidl
package com.clc.app5;
import com.clc.app5.City;
// Declare any non-default types here with import statements
interface IRemoteService {
/**
* 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);
City getCity();
}
=================================
package com.clc.app5;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class MyService1 extends Service {
public MyService1() {
}
IRemoteService.Stub binder = new IRemoteService.Stub(){
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
//service--data-->activity
//就把数据设置成返回值,返回给调用处
@Override
public City getCity() throws RemoteException {
return new City(123,"nanjing");
}
};
@Override
public IBinder onBind(Intent intent) {
return binder;
}
}
把serverAPP中aidl以及相关的实体类连同包一起复制到clientAPP中
然后在clientAPP中调用:
=========================================
『MainActivity』
//执行一次bindService后,再执行bindService就不会触发该方法;除非unbind后再次bind
//一次bind,对应一次执行,也就是一次性操作
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
IRemoteService iRemoteService = IRemoteService.Stub.asInterface(iBinder);
try {
City city = iRemoteService.getCity();
Log.d(TAG, "onServiceConnected: "+city.cityId+city.cityName);
} catch (RemoteException e) {
e.printStackTrace();
}
}
// IRemoteService.aidl
package com.clc.app5;
import com.clc.app5.City;
// Declare any non-default types here with import statements
interface IRemoteService {
/**
* 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);
//AIDL支持的数据类型默认in,其他显示加上in/out/inout
void setCity(in City city);
}
================
package com.clc.app5;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class MyService1 extends Service {
public static final String TAG = "MyService1";
public MyService1() {
}
/*
初步理解
activity与service的通信,归根结底是通过调用IRemoteService.Stub中的方法实现的
service--data-->activity:设置方法的返回值,在service中返回对象,在activity中获取
activity--data-->service:设置方法的参数,在activity调用时传入,在service中获取
*/
IRemoteService.Stub binder = new IRemoteService.Stub(){
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
//activity--data-->service
//就把数据设置成参数,在调用处传入数据
@Override
public void setCity(City city) throws RemoteException {
Log.d(TAG, "setCity: "+city.cityId+city.cityName);
}
};
@Override
public IBinder onBind(Intent intent) {
return binder;
}
}
=========================
『MainActivity』
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
IRemoteService iRemoteService = IRemoteService.Stub.asInterface(iBinder);
try {
iRemoteService.setCity(new City(12334,"nanjing"));
} catch (RemoteException e) {
e.printStackTrace();
}
}
// IRemoteService.aidl
package com.clc.app5;
import android.os.Bundle;
// Declare any non-default types here with import statements
interface IRemoteService {
/**
* 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);
//AIDL支持的数据类型默认in,其他显示加上in/out/inout
void setBundle(in Bundle bundle);
}
=====================================
『service的new IRemoteService.Stub(){}中』
@Override
public void setBundle(Bundle bundle) throws RemoteException {
/*
如果您的 AIDL 接口包含接收软件包作为参数(预计包含 Parcelable 类型)的方法,则在尝试从软件包读取之前,
请务必通过调用 Bundle.setClassLoader(ClassLoader) 设置软件包的类加载器。
否则,即使您在应用中正确定义 Parcelable 类型,也会遇到 ClassNotFoundException。
*/
bundle.setClassLoader(getClass().getClassLoader());
City city = bundle.getParcelable("city");
Log.d(TAG, "setBundle: "+city.cityId+city.cityName);
}
============================
『MainActivity』
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
IRemoteService iRemoteService = IRemoteService.Stub.asInterface(iBinder);
Bundle bundle = new Bundle();
bundle.putParcelable("city",new City(1233,"nanjingggggggggggggggggggggggggggggggg"));
try {
iRemoteService.setBundle(bundle);
} catch (RemoteException e) {
e.printStackTrace();
}
}