AIDL(Android Interface Definition Language)是Android系统自定义的接口描述语言。可以用来实现进程间的通讯。
通过file->new->aidl,来生成像对应的.aidl对应的文件,本文要实现两个不同的app通信。要想实现两个app的通信,那么就要实现app同样的接口。要完全一样,什么意思呢?里面的代码要完全一样。
// ITestAIDL.aidl
package iflytek.com.clientcode;//服务端和客户端也要一样
// Declare any non-default types here with import statements
interface ITestAIDL {
void addBook(in String book);
List<String> getBookList();
}
// ITestAIDL.aidl
package iflytek.com.clientcode; //服务端和客户端也要一样
// Declare any non-default types here with import statements
interface ITestAIDL {
void addBook(in String book);
List<String> getBookList();
}
两者的代码也要完全一摸一样,包括package ,若是package不一样,会报错,可以通过新建包名的方式来实现package一样。如下图:左边时服务端,右边客户端
若两端的代码不一致,会出现下面的错误:
Binder invocation to an incorrect interface
AIDL 支持下列数据类型:
- Java 编程语言中的所有原语类型(如 int、long、char、boolean 等等)
- String
- CharSequence
- List
- List 中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。 可选择将 List 用作“通用”类(例如,List)。另一端实际接收的具体类始终是 ArrayList,但生成的方法使用的是 List 接口。
- Map
Map 中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。 不支持通用 Map(如 Map形式的 Map)。 另一端实际接收的具体类始终是 HashMap,但生成的方法使用的是 Map 接口。
这些数据类型可能无法满足我们的要求,我们需要出书更复杂的数据,如何定义这些数据呢?需要两步:
1.在对应的package路径下model,这个model就是我服务端和客户端要传输的数据,并继承Parcelable,如下:
package iflytek.com.clientcode;
import android.os.Parcel;
import android.os.Parcelable;
public class Book implements Parcelable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Book(String name) {
this.name = name;
}
protected Book(Parcel in) {
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
}
}
2.这是需要重新定义一个aidl,名字为IBookAIDL.aidl,删除里面的数据,处理package那行,如下图
// IBookAIDL.aidl
package iflytek.com.clientcode;
// Declare any non-default types here with import statements
parcelable Book;
客服端代码
public class MainActivity extends AppCompatActivity {
private ITestAIDL iTestAIDL;
private boolean connected;
private List<String> bookList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bindService();
setContentView(R.layout.activity_main);
TextView textView = findViewById(R.id.hello_world);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
iTestAIDL.addBook("书籍");
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iTestAIDL = ITestAIDL.Stub.asInterface(service);
connected = true;
Toast.makeText(getApplicationContext(), "绑定成功!+true", Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceDisconnected(ComponentName name) {
connected = false;
Toast.makeText(getApplicationContext(), "绑定成功!+false" + name, Toast.LENGTH_SHORT).show();
Log.i("haochen", name + "被杀死");
bindService();
}
};
服务端代码:
public class MyService extends Service {
private List<String> books;
@Nullable
@Override
public IBinder onBind(Intent intent) {
books = new ArrayList<>();
return iBinder;
}
private IBinder iBinder = new ITestAIDL.Stub() {
@Override
public void addBook(String book) throws RemoteException {
books.add(book);
Log.i("haochen", "msg" + book);
}
@Override
public List<String> getBookList() throws RemoteException {
Toast.makeText(getApplicationContext(), "server get", Toast.LENGTH_SHORT).show();
return books;
}
};
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}
值得注意是再生成服务端和客户端的aidl文件时,代码要完全一样,包的路径也要完全一样,否则会包上面的错误。
githubDemo代码