Android跨进程通信(IPC机制 二)

在上个小节中,我们学习了AIDL的基本用法,这里先来回顾一下大致流程:首先创建一个Service和一个AIDL接口,接着创建一个类继承自AIDL中的Sub类并实现Sub类中的抽象方法,在Service中的onBind方法中返回这个类的对象,然后客户端就可以绑定服务端Service,建立连接后就可以访问远程服务端的方法了。

如果我们的项目中只有一个业务模块需要用到AIDL进行跨进程通信的话,上述方式完全可以应对。但随着我们项目日益庞大,现在有多个业务模块需要进行跨进程通信,该怎么解决呢?当然按照上述方式对每个模块一个一个按部就班也是可以的,不过这样子的话,我们的项目中就会存在多个进程,这显然不是最优的解决方式。我们可不可以只创建一个远程服务端进程来管理多个AIDL呢?答案是可以的,下面我们就一起来学习下Binder连接池。

为了说明问题,在这里我们提供两个AIDL接口(IDataOne 和 IDataTwo)用来模拟两个业务模块,分别用来处理 数据加减运算和数据乘除运算。声明如下:

// IDataOne.aidl
package com.example.administrator.binderpooltest;

interface IDataOne {
    int add(int a, int b);
    int minus(int a, int b);
}
// IDataTwo.aidl
package com.example.administrator.binderpooltest;

interface IDataTwo {
   int multiply(int a, int b);
   int divide(int a, int b);
}

上面两个AIDL接口实现代码如下:

package com.example.administrator.binderpooltest;

import android.os.RemoteException;

public class DataOneImpl extends IDataOne.Stub{

    @Override
    public int add(int a, int b) throws RemoteException {
        return a + b;
    }

    @Override
    public int minus(int a, int b) throws RemoteException {
        return a - b;
    }
}
package com.example.administrator.binderpooltest;

import android.os.RemoteException;

public class DataTwoImpl extends IDataTwo.Stub{

    @Override
    public int multiply(int a, int b) throws RemoteException {
        return a * b;
    }

    @Override
    public int divide(int a, int b) throws RemoteException {
        return a / b;        // 暂不考虑b为0的情况
    }
}

现在业务模块的AIDL接口定义和实现都已经完成了,接下来我们来看下服务端和Binder连接池的代码实现:

首先为Binder连接池创建AIDL接口IBinderPool :

// IBinderPool.aidl
package com.example.administrator.binderpooltest;

interface IBinderPool {
    IBinder queryBinder(int binderCode);
}

接着为Binder连接池创建远程Service并实现IBinderPool ,代码如下:

package com.example.administrator.binderpooltest;

public class Contat {
    public static final int BINDER_DATA_ONE = 1;
    public static final int BINDER_DATA_TWO = 2;
}
package com.example.administrator.binderpooltest;

import android.os.IBinder;
import android.os.RemoteException;

public class BinderPoolImpl extends IBinderPool.Stub{

    @Override
    public IBinder queryBinder(int binderCode) throws RemoteException {
        IBinder binder = null;
        switch (binderCode){
            case Contat.BINDER_DATA_ONE:
                binder = new DataOneImpl();
                break;

            case Contat.BINDER_DATA_TWO:
                binder = new DataTwoImpl();
                break;

            default:
                break;
        }
        return binder;
    }
}
package com.example.administrator.binderpooltest;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;

public class BinderPoolService extends Service{

    private Binder mBinderPool = new BinderPoolImpl();

    @Override
    public void onCreate() {
        super.onCreate();
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

记得Service需要在manifest文件中声明:


接下来看下Binder连接池的具体实现:

package com.example.administrator.binderpooltest;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;

import java.util.concurrent.CountDownLatch;

public class BinderPool {

    private static final String TAG = "BinderPool";

    private Context mContext;
    private IBinderPool mBinderPool;
    private static volatile BinderPool mInstance;
    private CountDownLatch mCountDownLatch;

    private BinderPool(Context context){
        mContext = context.getApplicationContext();
        connectBinderPoolService();
    }

    public static BinderPool getmInstance(Context context){
        if (mInstance == null){
            synchronized (BinderPool.class){
                if (mInstance == null){
                    mInstance = new BinderPool(context);
                }
            }
        }
        return mInstance;
    }

    private synchronized void connectBinderPoolService(){
        mCountDownLatch = new CountDownLatch(1);
        Intent intent = new Intent(mContext,BinderPoolService.class);
        mContext.bindService(intent,mBinderPoolConnection,Context.BIND_AUTO_CREATE);
        try {
            mCountDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public IBinder queryBinder(int binderCode){
        IBinder binder = null;

        try {
            if (mBinderPool != null) {
                binder = mBinderPool.queryBinder(binderCode);
            }
        }catch (RemoteException e){
            e.printStackTrace();
        }
        return binder;
    }

    private ServiceConnection mBinderPoolConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBinderPool = IBinderPool.Stub.asInterface(service);
            try {
                mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient,0);
            }catch (RemoteException e){
                e.printStackTrace();
            }
            mCountDownLatch.countDown();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            if (mBinderPool != null){
                mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient,0);
            }
            mBinderPool = null;
            connectBinderPoolService();
        }
    };
}

下面我们在客户端来验证一下,客户端代码编写如下:

package com.example.administrator.binderpooltest;

import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private Button mDataOneTest;
    private Button mDataTwoTest;

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

        initView();
        initListener();
    }

    private void initView(){
        mDataOneTest = (Button) findViewById(R.id.mDataOneTest);
        mDataTwoTest = (Button) findViewById(R.id.mDataTwoTest);
    }

    private void initListener(){
        mDataOneTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        BinderPool binderPool = BinderPool.getmInstance(MainActivity.this);
                        IBinder dataOneBinder = binderPool.queryBinder(Contat.BINDER_DATA_ONE);
                        IDataOne mDataOne = IDataOne.Stub.asInterface(dataOneBinder);
                        try {
                            int addResult = mDataOne.add(2,3);
                            Log.e(TAG,"result 2 + 3 = "+addResult);
                            int minusResult = mDataOne.minus(8,2);
                            Log.e(TAG,"result 8 - 2 = "+minusResult);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        });

        mDataTwoTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        BinderPool binderPool = BinderPool.getmInstance(MainActivity.this);
                        IBinder dataTwoBinder = binderPool.queryBinder(Contat.BINDER_DATA_TWO);
                        IDataTwo mDataTwo = IDataTwo.Stub.asInterface(dataTwoBinder);
                        try {
                            int multiplyResult = mDataTwo.multiply(2,3);
                            Log.e(TAG,"result 2 * 3 = "+multiplyResult);
                            int divideResult = mDataTwo.divide(8,2);
                            Log.e(TAG,"result 8 / 2 = "+divideResult);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        });
    }
}

分别点击按钮,测试结果如下:

09-02 00:18:32.185 17275-18727/com.example.administrator.binderpooltest E/MainActivity: result 2 + 3 = 5
09-02 00:18:32.185 17275-18727/com.example.administrator.binderpooltest E/MainActivity: result 8 - 2 = 6
09-02 00:18:33.845 17275-18754/com.example.administrator.binderpooltest E/MainActivity: result 2 * 3 = 6
09-02 00:18:33.845 17275-18754/com.example.administrator.binderpooltest E/MainActivity: result 8 / 2 = 4

可以看到程序正常运行。由此可见,Binder连接池能够极大提高AIDL的开发效率,并且可以避免大量的Service创建,建议我们在AIDL开发工作中引入BinderPool机制。

你可能感兴趣的:(Android跨进程通信(IPC机制 二))