Android Binder机制理解

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;
}

(完)

你可能感兴趣的:(Android Binder机制理解)