Binder是Android系统IPC通信的一种模型,要实现进程间通信方式很多,有Bundle、文件共享、Messager、AIDL、ContentProvider、Socket。AIDL就是根据Binder通信模型精简的接口语言。使用AIDL编译成功后会生成一个java文件,内部对IBinder接口有具体的实现。
自行实现Binder通讯
场景一:Client端调用Server端方法并获得返回内容
Server端代码:
public class BinderService extends Service {
private static final String TAG = BinderService.class.getName();
// 服务端执行的业务逻辑
private String testStart(String tag, int data) {
Log.i("XXXXXXX", "-------- TestBinder -------- tag:" + tag + " data:" + data);
return "back from service is " + tag + ":" + data;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new TestBinder();
}
class TestBinder extends Binder {
// 服务端接受客户端的请求
@Override
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
switch (code) {
case 1001:
String testStr = data.readString();
int testInt = data.readInt();
String result = testStart(testStr, testInt);
reply.writeNoException();
reply.writeString(result);
return true;
}
return super.onTransact(code, data, reply, flags);
}
}
}
Server端通过onTransact方法响应Client的调用,通过code判断具体是哪个任务并进行业务处理。
Client端代码:
private IBinder clientBinder;
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
clientBinder = iBinder;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
test_binder = findViewById(R.id.test_binder);
test_binder.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (clientBinder != null) {
Parcel data = Parcel.obtain();
// 必须按约定顺序填充参数
data.writeString("testFlag");
data.writeInt(10);
Parcel reply = Parcel.obtain();
try {
clientBinder.transact(1001, data, reply, 0);
reply.readException();
Log.i("XXXXXXX", reply.readString());
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Toast.makeText(MainActivity.this, "clientBinder 为空", Toast.LENGTH_SHORT).show();
}
}
});
Intent intent = new Intent(this, BinderService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
Client端通过transact方法向Binder传递code、参数等,通过readXXX方法读取Server返回的数据。
场景二:Server端执行了耗时操作,需要将处理结果返回Client端
Server端代码:
public class BinderService extends Service {
private static final String TAG = BinderService.class.getName();
// 服务端执行的业务逻辑
private void runTask(final IBinder binder) {
new Thread() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i("XXXXXXX", "BinderService Binder:" + binder.toString());
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
binder.transact(2001, data, reply, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}.start();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new TestBinder();
}
class TestBinder extends Binder {
// 服务端接受客户端的请求
@Override
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
switch (code) {
case 1002:
// 获取客户端Binder
IBinder binder = data.readStrongBinder();
runTask(binder);
int result2 = 1;
// 将返回的结果发送回去
reply.writeNoException();
reply.writeInt(result2);
return true;
}
return super.onTransact(code, data, reply, flags);
}
}
}
Server端通过readStrongBinder方法获取Client传递过来的Binder对象,耗时任务处理完后,会通过Binder对象transact方法向Client端发送处理结果。
Client端代码:
private IBinder clientBinder;
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
clientBinder = iBinder;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
static class ClientBinder extends Binder {
/** 接受客户端的请求 **/
@Override
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
switch (code) {
case 2001:
Log.i("XXXXXXX", "-------Client Client------------");
return true;
}
return super.onTransact(code, data, reply, flags);
}
}
test_binder_timeconsuming = findViewById(R.id.test_binder_timeconsuming);
test_binder_timeconsuming.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (clientBinder != null) {
Parcel data = Parcel.obtain();
ClientBinder binderProxy = new ClientBinder();
Log.i("XXXXXXX", "MainActivity Binder:" + binderProxy.toString());
data.writeStrongBinder(binderProxy);
Parcel reply = Parcel.obtain();
try {
clientBinder.transact(1002, data, reply, 0);
reply.readException();
Log.i("XXXXXXX", "result2 is " + reply.readInt());
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Toast.makeText(MainActivity.this, "clientBinder 为空", Toast.LENGTH_SHORT).show();
}
}
});
Intent intent = new Intent(this, BinderService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
Client定义传递的BinderProxy,通过writeStrongBinder方法将BinderProxy设置进参数中,这里的Binder对象和Server端的Binder对象是同一个对象,内存地址也一样。
详情参考:https://www.jianshu.com/p/09f2ecb8237a
AIDL实现Binder通讯
AIDL定义实体对象:
AIDL定义的Bean.aidl和Bean.java包名要一致,否则生成的java处理类报Bean找不到
定向tag:
inout:说明该实体可以被Client、Server同时访问,一端更改属性后,另一端的属性值也会跟随更改。但两个实体对象不一样,因为已经经过序列化和反序列化。
in:数据只能从Client端流向Server端,Server端改动数据的值,Client端不会进行同步更改。
out:数据只能从Server端流向Client端,Server端无法获取Client端传递过来的属性的值,但可以获得整个对象;Server端更改属性值后,Client端的属性值会跟随更改。
数据传递事以Parcel类型进行传输。
详情参考:https://www.jianshu.com/p/29999c1a93cd
AIDL生成的JAVA文件详解
静态类Stub实际上事一个Binder对象,内部onTransact根据不同的code执行不同的业务处理,reply事返回的数据对象。
asInterface方法返回这个生成的java对象,通过该对象可以直接调用AIDL文件中定义的方法。
静态内部类Proxy实际上是一个封装,内部封装了Client端执行AIDL定义的方法的具体实现,包括组装参数,填充code等,组装成功后调用transact方法向Server端发送数据,并通过reply对象获取处理后的结果返回Client端。
public interface BookController extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.viomi.testbinder.BookController {
private static final java.lang.String DESCRIPTOR = "com.viomi.testbinder.BookController";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.viomi.testbinder.BookController interface,
* generating a proxy if needed.
*/
public static com.viomi.testbinder.BookController asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.viomi.testbinder.BookController))) {
return ((com.viomi.testbinder.BookController) iin);
}
return new com.viomi.testbinder.BookController.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 {
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
case TRANSACTION_getBookList: {
data.enforceInterface(descriptor);
java.util.List _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBookInOut: {
data.enforceInterface(descriptor);
com.viomi.testbinder.entity.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.viomi.testbinder.entity.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBookInOut(_arg0);
reply.writeNoException();
if ((_arg0 != null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_addBookIn: {
data.enforceInterface(descriptor);
com.viomi.testbinder.entity.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.viomi.testbinder.entity.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBookIn(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_addBookOut: {
data.enforceInterface(descriptor);
com.viomi.testbinder.entity.Book _arg0;
_arg0 = new com.viomi.testbinder.entity.Book();
this.addBookOut(_arg0);
reply.writeNoException();
if ((_arg0 != null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com.viomi.testbinder.BookController {
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 java.util.List getBookList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.viomi.testbinder.entity.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addBookInOut(com.viomi.testbinder.entity.Book book) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book != null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBookInOut, _data, _reply, 0);
_reply.readException();
if ((0 != _reply.readInt())) {
book.readFromParcel(_reply);
}
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void addBookIn(com.viomi.testbinder.entity.Book book) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book != null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBookIn, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void addBookOut(com.viomi.testbinder.entity.Book book) 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_addBookOut, _data, _reply, 0);
_reply.readException();
if ((0 != _reply.readInt())) {
book.readFromParcel(_reply);
}
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBookInOut = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_addBookIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_addBookOut = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
}
public java.util.List getBookList() throws android.os.RemoteException;
public void addBookInOut(com.viomi.testbinder.entity.Book book) throws android.os.RemoteException;
public void addBookIn(com.viomi.testbinder.entity.Book book) throws android.os.RemoteException;
public void addBookOut(com.viomi.testbinder.entity.Book book) throws android.os.RemoteException;
}
(完)