十五 、 Android 中的 IPC 之 AIDL 补充 --- 使用 Binder 连接池

    在 Android 多进程通信中,我们使用最多的就是 AIDL。前面我们已经说过了 AIDL 的具体使用方法,客户端连接服务端的 Service,然后通过服务端返回的 Binder 再结合 AIDL 类型接口即可让客户端调用到服务端中的方法并与之进行通信,使用起来很简单。试想一下,如果服务端定义了多个 AIDL 接口,一个 AIDL 接口绑定一个 Service,那岂不是在服务端要开启多个后台 Service,10 个还能接受,100个呢?1000个呢?所以显然这样是不可行的。

    而我们的解决方案就是通过定义一个 IBinderPool 这样的 AIDL 接口对服务端所有的 AIDL 接口进行管理,然后服务端只需要创建一个与 IBinderPool 绑定的 Service,客户端就像可以通过绑定这一个 Service 即可获取想要的 AIDL 类型接口然后进行相应的方法调用。思想很简单,就类似买房和卖房一样,比如桂芳园小区的每一户房屋就相当于服务端的多个 AIDL 接口,小区旁边的链家房产中介就相当于服务端的 IBinderPool 接口,卖房的人把房产信息挂到链家中介,而我们想买房的人只需要找链家中介即可。也就是客户端获取到 IBinderPool 就可以调用我们想调用的 AIDL 接口。下面看一下具体实现:

ICalculate1.aidl:

// ICalculate1.aidl
package com.cfm.binderpooltest;

interface ICalculate1 {
    // 提供加减法的计算器 1
    int add(int a, int b);
    int subtraction(int a, int b);
}

ICalculate2.aidl:

// ICalculate2.aidl
package com.cfm.binderpooltest;

interface ICalculate2 {
    // 提供乘除法的计算器 2
    int multip(int a, int b);
    int division(int a, int b);
}

IBinderPool.aidl:

// IBinderPool.aidl
package com.cfm.binderpooltest;

interface IBinderPool {
    IBinder queryBinder(int binderCode);
}

Calculate1Impl.java:

package com.cfm.binderpooltest;

/**
* 第一个 AIDL 接口的具体实现类
*/
public class Calculate1Impl extends ICalculate1.Stub {
    private static final String TAG = "cfmtest";

    @Override
    public int add(int a, int b) throws RemoteException {
        Log.d(TAG, "服务端开始计算加法");
        return (a+b);
    }

    @Override
    public int subtraction(int a, int b) throws RemoteException {
        Log.d(TAG, "服务端开始计算减法");
        return (a-b);
    }
}

Calculate2Impl.java:

package com.cfm.binderpooltest;

/**
*  第二个 AIDL 接口的具体实现类
*/
public class Calculate2Impl extends ICalculate2.Stub {
    private static final String TAG = "cfmtest";

    @Override
    public int multip(int a, int b) throws RemoteException {
        Log.d(TAG, "服务端开始计算乘法");
        return (a*b);
    }

    @Override
    public int division(int a, int b) throws RemoteException {
        Log.d(TAG, "服务端开始计算除法");
        return (a/b);
    }
}

BinderPoolService.java:(服务端)

package com.cfm.binderpooltest;

public class BinderPoolService extends Service {
    private static final String TAG = "cfmtest";
    private static final int BINDER_CALCULATE_1 = 1;
    private static final int BINDER_CALCULATE_2 = 2;
    private IBinder mBinderPool;

    public BinderPoolService() {

    }

    @Override
    public void onCreate() {
        Log.d(TAG, "客户端绑定服务成功!");
        super.onCreate();
        mBinderPool = new BinderPoolImpl();
    }

    /**
     *  客户端所获取到的 IBinder 接口,然后通过传入请求操作的 AIDL 接口对应的
     *  标示符,获取到相应的 AIDL 接口类型实例。
     */
    private class BinderPoolImpl extends IBinderPool.Stub {

        @Override
        public IBinder queryBinder(int binderCode) throws RemoteException {
            IBinder binder = null;
            switch (binderCode) {
                case BINDER_CALCULATE_1:
                    binder = new Calculate1Impl();
                    break;
                case BINDER_CALCULATE_2:
                    binder = new Calculate2Impl();
                    break;
                default:
                    break;
            }
            return binder;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinderPool;
    }
}

ClientActivity.java:(客户端)

package com.cfm.binderpooltest;

public class ClientActivity extends AppCompatActivity {
    private static final String TAG = "cfmtest";
    private static final int BINDER_CALCULATE_1 = 1;
    private static final int BINDER_CALCULATE_2 = 2;

    private ServiceConnection conn = new ServiceConnection() {
        
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 客户端连接服务端后返回的 Binder 类型是 IBinderPool
            IBinderPool binderPool = IBinderPool.Stub.asInterface(service);
            // 然后我们再调用 IBinderPool 中的 queryBinder 方法获取我们想要使用的 AIDL 接口
            try {
                ICalculate1 iCalculate1 = ICalculate1.Stub.asInterface(binderPool.queryBinder(BINDER_CALCULATE_1));
                ICalculate2 iCalculate2 = ICalculate2.Stub.asInterface(binderPool.queryBinder(BINDER_CALCULATE_2));
                Log.d(TAG, "客户端计算 6 加 2 为: " + iCalculate1.add(6, 2) );
                Log.d(TAG, "客户端计算 6 减 2 为: " + iCalculate1.subtraction(6, 2) );
                Log.d(TAG, "客户端计算 6 乘 2 为: " + iCalculate2.multip(6, 2) );
                Log.d(TAG, "客户端计算 6 除 2 为: " + iCalculate2.division(6, 2) );
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_client);

        // 绑定服务端
        Intent intent = new Intent(this, BinderPoolService.class);
        bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }
}

AndroidManifest.xml:

...
        <service
            android:name=".BinderPoolService"
            android:enabled="true"
            android:exported="true"
            android:process=".remote">
        </service>

        <activity android:name=".ClientActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
...

Log 打印信息:

服务端:

2019-05-27 21:33:06.790 15680-15680/.remote D/cfmtest: 客户端绑定服务成功!
2019-05-27 21:33:06.853 15680-15695/.remote D/cfmtest: 服务端开始计算加法
2019-05-27 21:33:06.854 15680-15695/.remote D/cfmtest: 服务端开始计算减法
2019-05-27 21:33:06.856 15680-15695/.remote D/cfmtest: 服务端开始计算乘法
2019-05-27 21:33:06.857 15680-15695/.remote D/cfmtest: 服务端开始计算除法

客户端:

2019-05-27 21:33:06.854 15661-15661/com.cfm.binderpooltest D/cfmtest: 客户端计算 6 加 2 为: 8
2019-05-27 21:33:06.855 15661-15661/com.cfm.binderpooltest D/cfmtest: 客户端计算 6 减 2 为: 4
2019-05-27 21:33:06.857 15661-15661/com.cfm.binderpooltest D/cfmtest: 客户端计算 6 乘 2 为: 12
2019-05-27 21:33:06.858 15661-15661/com.cfm.binderpooltest D/cfmtest: 客户端计算 6 除 2 为: 3

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值